I am new to multithread programming. I tried to print sequence of numbers using even and odd number printing threads, running in parallel. When executed, the code enters a deadlock. Can anyone help me to solve this.
#include<stdio.h>
#include<pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t even, odd;
void printfun1(void *pnt);
void printfun2(void *pnt);
main()
{
pthread_t pthread1, pthread2;
int ret1, ret2;
char *message = "thread 1";
char *message2 = "thread 2";
ret1 = pthread_create(&pthread1, NULL, printfun1, (void *)message);
if(ret1)
{
printf("thread creation failed");
}
ret2 = pthread_create(&pthread2, NULL, printfun2,(void*) message2);
if(ret2)
{
printf("thread creation failed");
}
pthread_join(pthread1, NULL);
pthread_join(pthread2, NULL);
exit(0);
}
void printfun1(void *ptr)
{
char* message = ptr;
int counter = -1;
while(counter < 50)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&even, &mutex);
counter += 2;
printf("%d \n", counter);
pthread_cond_signal(&odd);
pthread_mutex_unlock(&mutex);
usleep( 1000000);
}
}
void printfun2(void *ptr)
{
char* message = ptr;
int counter2 = 0;
pthread_cond_signal(&even);
while(counter2 < 50)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&odd, &mutex);
counter2 += 2;
printf("%d \n", counter2);
pthread_cond_signal(&even);
pthread_mutex_unlock(&mutex);
usleep( 1000000);
}
}
There are at least a couple things wrong with the program:
You never initialize the condition variables:
pthread_cond_init(&even, NULL); pthread_cond_init(&odd, NULL);
You can reach a deadlock if you signal a condition when the other thread isn't waiting on that condition. Normally, when you use pthread_cond_wait()
, you also are checking some other shared variable in a while loop. I rewrote your program to demonstrate this:
#include <stdio.h> #include <pthread.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t even = PTHREAD_COND_INITIALIZER; pthread_cond_t odd = PTHREAD_COND_INITIALIZER; void *printfun1(void *pnt); void *printfun2(void *pnt); int main(void) { pthread_t pthread1, pthread2; int ret1, ret2; ret1 = pthread_create(&pthread1, NULL, printfun1, NULL); if(ret1) { printf("thread creation failed"); } ret2 = pthread_create(&pthread2, NULL, printfun2, NULL); if(ret2) { printf("thread creation failed"); } pthread_join(pthread1, NULL); pthread_join(pthread2, NULL); } int counter = 0; void *printfun1(void *ptr) { while(counter < 50) { pthread_mutex_lock(&mutex); while ((counter & 1) == 1) pthread_cond_wait(&even, &mutex); printf("%d \\n", counter); counter++; pthread_cond_signal(&odd); pthread_mutex_unlock(&mutex); usleep( 1000000); } return NULL; } void *printfun2(void *ptr) { while(counter < 50) { pthread_mutex_lock(&mutex); while ((counter & 1) == 0) pthread_cond_wait(&odd, &mutex); printf("%d \\n", counter); counter++; pthread_cond_signal(&even); pthread_mutex_unlock(&mutex); usleep( 1000000); } return NULL; }
Now you can see how deadlock is avoided. A thread only starts waiting on a condition when it knows that it needs to wait on the condition. So even if the second thread signalled the condition when the first thread wasn't waiting on it, it doesn't matter.
I think that to do the job right, you need three mutexes and three condition variables. The odd thread must keep the odd mutex locked for the entire duration of the program. The only time the odd mutex is unlocked is when the odd thread is waiting on its condition. Likewise, the even thread needs to keep the even mutex locked for the duration.
And you need a main mutex and a main condition variable, so that the odd and even threads can signal main after locking their respective mutexes.
After the odd and even threads
- are up and running
- have locked their mutexes
- and are waiting on their condition variables (which unlocks the mutex)
then main
can signal the odd thread one time to get things started.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mainMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t oddMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t evenMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mainCond = PTHREAD_COND_INITIALIZER;
pthread_cond_t oddCond = PTHREAD_COND_INITIALIZER;
pthread_cond_t evenCond = PTHREAD_COND_INITIALIZER;
void *printOdd( void *arg )
{
pthread_mutex_lock( &oddMutex ); // grab the odd mutex
pthread_mutex_lock( &mainMutex ); // signal main that the odd thread
pthread_cond_signal( &mainCond ); // is locked and ready for action
pthread_mutex_unlock( &mainMutex );
for ( int counter = 1; counter < 50; counter += 2 )
{
pthread_cond_wait( &oddCond, &oddMutex ); // wait for the odd signal
printf( "%d\n", counter );
pthread_mutex_lock( &evenMutex ); // signal the even thread
pthread_cond_signal( &evenCond );
pthread_mutex_unlock( &evenMutex );
usleep( 100000 );
}
pthread_mutex_unlock( &oddMutex );
return NULL;
}
void *printEven( void *arg )
{
pthread_mutex_lock( &evenMutex ); // grab the even mutex
pthread_mutex_lock( &mainMutex ); // signal main that the even thread
pthread_cond_signal( &mainCond ); // is locked and ready for action
pthread_mutex_unlock( &mainMutex );
for ( int counter = 2; counter < 50; counter += 2 )
{
pthread_cond_wait( &evenCond, &evenMutex ); // wait for the even signal
printf( "%d\n", counter );
pthread_mutex_lock( &oddMutex ); // signal the odd thread
pthread_cond_signal( &oddCond );
pthread_mutex_unlock( &oddMutex );
usleep( 100000 );
}
pthread_mutex_unlock( &evenMutex );
return NULL;
}
int main( void )
{
pthread_t id1, id2;
pthread_mutex_lock( &mainMutex ); // grab the main mutex
if ( pthread_create( &id1, NULL, printOdd, NULL ) != 0 ) // create the odd thread
exit( 1 );
pthread_cond_wait( &mainCond, &mainMutex ); // wait for the signal from the odd thread
if ( pthread_create( &id2, NULL, printEven, NULL ) != 0 ) // create the even thread
exit( 1 );
pthread_cond_wait( &mainCond, &mainMutex ); // wait for the signal from the even thread
pthread_mutex_unlock( &mainMutex ); // startup has completed, release the main mutex
pthread_mutex_lock( &oddMutex ); // signal the odd thread to get things rolling
pthread_cond_signal( &oddCond );
pthread_mutex_unlock( &oddMutex );
pthread_join( id1, NULL ); // wait for the threads to finish
pthread_join( id2, NULL );
exit( 0 );
}
First thing is condition variable is not initialized to "PTHREAD_COND_INTIALIAZER". Coming to the program, in the first thread, i think pthread_mutex_unlock should come before pthread_cond_signal
the following code --removes the unneeded system function calls --properly handles the mutex creation/locking/unlocking/destruction --prints even/odd values from 0 through 49 --properly handles logging of errors --corrects the compiler warning about undefined function exit() --stops threads getting locked in the inner while loop --properly defines the top thread functions as 'void*' rather than 'void' --properly sets parameters to pthread_create() --properly exits the threads via pthread_exit() --and several other minor fixes
#include <stdio.h>
#include <stdlib.h> // exit(), EXIT_FAILURE
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *printfun1(void *);
void *printfun2(void *);
main()
{
pthread_t pthread1, pthread2;
int ret1, ret2;
ret1 = pthread_create(&pthread1, NULL, &printfun1, (void *)message);
if(ret1)
{
perror("thread 1 creation failed");
exit( EXIT_FAILURE );
}
ret2 = pthread_create(&pthread2, NULL, &printfun2,(void*) message2);
if(ret2)
{
perror("thread 2 creation failed");
exit( EXIT_FAILURE );
}
pthread_join(pthread1, NULL);
pthread_join(pthread2, NULL);
pthread_mutex_destroy(&mutex);
return 0;
} // end function: main
int counter = 0;
// Note:
// 1) 0 is even so should be printed
// 2) 50 is beyond the range, so should not be printed
// 3) use do{...}while so program will exit when done,
// rather than getting locked in wait loop
void *printfun1(void *ptr)
{
do
{
while( (counter & 1) == 0 )
{
usleep(100);
}
pthread_mutex_lock(&mutex);
printf("%d \n", counter);
counter++;
pthread_mutex_unlock(&mutex);
} while( counter < 50 );
pthread_exit( 0 );
} // end function: printfun1
void *printfun2(void *ptr)
{
do
{
while( (counter & 1) == 1 )
{
usleep(100);
}
pthread_mutex_lock(&mutex);
printf("%d \n", counter);
counter++;
pthread_mutex_unlock(&mutex);
} while( counter < 50 );
pthread_exit( 0 );
} // end function: printfun2
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.