I have a couple questions. This is my first real attempt at making a multithreaded program.
NOTE - the full program is at the bottom of the page
(to compile, use
g++ -pthread -o <executable file name> <sourcefile>.cpp -fpermissive
)
I compiled it using Ubuntu Studio 10.10 64 bit.
The biggest problem with this program is that it gives me a segmentation fault.
It seems to be caused by the line I commented in int main(). If I comment that line out, it doesn't give me a segmentation fault error.
Here's int main() alone for convenience:
int main()
{
pthread_attr_t attr;
pthread_t threads[30];
/* Initialize mutex and condition variable objects */
pthread_mutex_init(&direction_mutex, NULL);
pthread_mutex_init(&arrive_mutex,NULL);
pthread_cond_init (&count_threshold, NULL);
pthread_cond_init(&arrive_done, NULL);
/*
For portability, explicitly create threads in a joinable state
I'll take your word for it on that one.
*/
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for( int x = 0 ; x < 30 ; x++)
{
long random = rand();
int direction;
if (random < RAND_MAX/2)
{
direction = 0;
}
else
{
direction = 1;
}
directions[x] = direction;
printf("%d",direction);
}
printf("\n");
currdir = directions[0];
for(int j = 0 ; j < 30 ; j++)
{
if(j != 0)
{
pthread_cond_wait(&arrive_done, NULL); // THIS line of code is what is causing the problem
}
pthread_create(&threads[j], &attr, OneCar, (void *)&Thread_IDs[j]);
}
/* Wait for all threads to complete */
for (j = 0; j < 30; j++)
{
pthread_join(threads[j], NULL);
}
printf("test\n");
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&direction_mutex);
pthread_cond_destroy(&count_threshold);
pthread_exit (NULL);
}
Without that line, the program runs, but the problem is, it seems to go rather randomly in thread order.
I was trying to use that mutex lock to keep int main() from starting a new thread until the last one finished, since this program is supposed to have the threads run in FIFO order.
Without this code, it varies in behavior.
Most of the time it starts at thread 0, then goes to thread 3,4, sometimes even 5 before coming back to thread 1.
Sometimes, it starts at thread 3, then goes to thread 4, then thread 0... I can't figure out why it's doing that.
It's a different sequence of thread execution every time, but it's never 0,1,2,3,4 like it needs to be
Here's the output with the offending line commented out:
*** Output of program with "pthread_cond_wait(&arrive_done, NULL);" commented out:
101110010101011111010001000010
ArriveBridge(): Car 1 goes accross the bridge
ExitBridge(): car 1 has left the bridge
Arrivebridge(): Thead 0 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 0 goes accross the bridge
ExitBridge(): car 0 has left the bridge
Arrivebridge(): Thead 5 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 5 goes accross the bridge
ExitBridge(): car 5 has left the bridge
Arrivebridge(): Thead 3 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 3 goes accross the bridge
ExitBridge(): car 3 has left the bridge
ArriveBridge(): Car 2 goes accross the bridge
ExitBridge(): car 2 has left the bridge
ArriveBridge(): Car 4 goes accross the bridge
ExitBridge(): car 4 has left the bridge
Arrivebridge(): Thead 6 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 6 goes accross the bridge
ExitBridge(): car 6 has left the bridge
Arrivebridge(): Thead 7 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 7 goes accross the bridge
ExitBridge(): car 7 has left the bridge
Arrivebridge(): Thead 8 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 8 goes accross the bridge
ExitBridge(): car 8 has left the bridge
Arrivebridge(): Thead 9 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 9 goes accross the bridge
ExitBridge(): car 9 has left the bridge
Arrivebridge(): Thead 10 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 10 goes accross the bridge
ExitBridge(): car 10 has left the bridge
Arrivebridge(): Thead 11 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 11 goes accross the bridge
ExitBridge(): car 11 has left the bridge
ArriveBridge(): Car 13 goes accross the bridge
ExitBridge(): car 13 has left the bridge
Arrivebridge(): Thead 12 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 12 goes accross the bridge
ExitBridge(): car 12 has left the bridge
Arrivebridge(): Thead 14 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 14 goes accross the bridge
ExitBridge(): car 14 has left the bridge
ArriveBridge(): Car 15 goes accross the bridge
ExitBridge(): car 15 has left the bridge
ArriveBridge(): Car 16 goes accross the bridge
ExitBridge(): car 16 has left the bridge
Arrivebridge(): Thead 18 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 18 goes accross the bridge
ExitBridge(): car 18 has left the bridge
Arrivebridge(): Thead 17 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 17 goes accross the bridge
ExitBridge(): car 17 has left the bridge
ArriveBridge(): Car 19 goes accross the bridge
ExitBridge(): car 19 has left the bridge
Arrivebridge(): Thead 21 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 21 goes accross the bridge
ExitBridge(): car 21 has left the bridge
ArriveBridge(): Car 20 goes accross the bridge
ExitBridge(): car 20 has left the bridge
ArriveBridge(): Car 22 goes accross the bridge
ExitBridge(): car 22 has left the bridge
Arrivebridge(): Thead 23 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 23 goes accross the bridge
ExitBridge(): car 23 has left the bridge
Arrivebridge(): Thead 24 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 24 goes accross the bridge
ExitBridge(): car 24 has left the bridge
ArriveBridge(): Car 25 goes accross the bridge
ExitBridge(): car 25 has left the bridge
ArriveBridge(): Car 26 goes accross the bridge
ExitBridge(): car 26 has left the bridge
ArriveBridge(): Car 27 goes accross the bridge
ExitBridge(): car 27 has left the bridge
ArriveBridge(): Car 29 goes accross the bridge
ExitBridge(): car 29 has left the bridge
Arrivebridge(): Thead 28 is trying to go in the opposite direction, it must wait for traffic to clear
ArriveBridge(): Car 28 goes accross the bridge
ExitBridge(): car 28 has left the bridge
test
This is the output WITHOUT that line commented out
****output of program before commenting pthread_cond_wait(&arrive_done, NULL); out:
101110010101011111010001000010
Segmentation fault
As you can see, it fails almost immediately, before any threads are created.
The other thing I was trying to improve is that my sequence of zeros and ones is not very random. Is there a better way to get random numbers generated? It doesn't have to be extremely random, but this sequence is exactly the same every time.
Thanks for your time
You need to actually pass a mutex to pthread_cond_wait, you're passing NULL.
For random data (at least on linux) read from /dev/random or /dev/urandom. You can also try: direction = (rand() >> 8) & 1
Your main loop should be:
pthread_mutex_lock(&arrive_mutex);
for(int j = 0 ; j < 30 ; j++)
{
if(j != 0)
{
// Pass a locked mutex as the second parameter.
pthread_cond_wait(&arrive_done, &arrive_mutex);
// This releases the lock and suspends the thread.
// When the condition variable is signaled. It re-establishes the lock
// then releases the thread. If another processes is holding the lock
// the released thread is stalled until it can acquire the lock.
//
// This means the child thread should acquire the lock on the mutex.
// call signal and then release the lock. If the child does not
// aquire the lock first then there is the potential for the child to
// reach the signal before the parent waits() if this happens then the
// parent will suspend forever (as nobody else will signal).
}
pthread_create(&threads[j], &attr, OneCar, (void *)&Thread_IDs[j]);
}
// Unlock the mutex afterwords.
pthread_mutex_unlock(&arrive_mutex);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With