Search code examples
cmultithreadingpthreadsposixdeadlock

Problem in communication of three threads in C language (deadlock occurs)


I am creating a program in which i have 3 linked lists and I am trying to update or remove the nodes from these linked lists in these three threads. But the deadlock is occurring

The insertion and deletion is working fine. Here the three variables var1InUse,var2InUse and var3InUse are indicating that whether the 3 linked lists are in use or not(Not all three are use in the all threads). I am putting the threads on waiting based on var1InUse,var2InUse and var3InUse as you can see in the code. Sometimes this works fine but sometimes deadlock happens. I have searched for the solution on the internet but could find it. Am I using the wait and signal methods correctly?

    pthread variables declaration

    pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;

     pthread_cond_t t1cond = PTHREAD_COND_INITIALIZER;

     pthread_cond_t t2cond = PTHREAD_COND_INITIALIZER;  

     pthread_cond_t t3cond = PTHREAD_COND_INITIALIZER;

    int var1InUse=0,var2InUse=0,var3InUse=0;

THREAD 1

    void* thread1(void* args){
        while(var1InUse || var2InUse ) {
                pthread_cond_wait(&t1cond,&myMutex);}
        var1InUse=1,var2InUse=1;
        while(1){

                pthread_mutex_lock(&myMutex);
                /*
                some other code about adding and removing from                         
                       linkedlist
                */
        var1InUse=0,var2InUse=0;
        pthread_cond_signal(&t2cond);
        pthread_cond_signal(&t3cond);
        pthread_mutex_unlock(&myMutex);}
     }

THREAD 2

    void* thread2(void* args){
        while(var1InUse || var2InUse || var3InUse) {
                pthread_cond_wait(&t2cond,&myMutex);}
        var1InUse=1,var2InUse=1,var3InUse=1;
        while(1){

                pthread_mutex_lock(&myMutex);
                /*
                some other code adding and removing from linkedlist
                */
                var1InUse=0,var2InUse=0,var3InUse=0;
                pthread_cond_signal(&t1cond);
                pthread_cond_signal(&t3cond);
                pthread_mutex_unlock(&myMutex);}
                    }

THREAD 3

     void* thread3(void* args){
        while(var1InUse || var3InUse ) {
                pthread_cond_wait(&t3cond,&myMutex);}
        var1InUse=1,var3InUse=1;
        while(1){

                pthread_mutex_lock(&myMutex);
                /*
                some other code adding and removing from linkedlist
                */
        var1InUse=0,var3InUse=0;
        pthread_cond_signal(&t1cond);
        pthread_cond_signal(&t2cond);
        pthread_mutex_unlock(&myMutex);}
            }

MAIN METHOD

    int main(){
        pthread_t t1,t2,t3,t4;
        pthread_mutex_init(&myMutex,0);
        pthread_create(&t1,NULL,thread1,NULL);
        pthread_create(&t2,NULL,thread2,NULL);
        pthread_create(&t3,NULL,thread3,NULL);
        pthread_join(t1,NULL); 
        pthread_join(t2,NULL);
            pthread_join(t3,NULL);
        pthread_mutex_destroy(&myMutex);
        return 0
            }

I want the deadlock to be removed.


Solution

  • The mutex used by pthread_cond_wait() needs to locked before the function is called. Here is an extract from the man page:

    The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. The application shall ensure that these functions are called with mutex locked by the calling thread; otherwise, an error (for PTHREAD_MUTEX_ERRORCHECK and robust mutexes) or undefined behavior (for other mutexes) results.

    Although pthread_cond_wait() unlocks the mutex internally, it is locked again before the function returns successfully:

    Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.

    Additionally, you should access the shared variables var1InUse, var2InUse and var3InUse with the mutex locked.

    Here is a modified version of your thread1() that follows these rules. The modifications to the other thread start routines should be similar:

    void* thread1(void* args){
    
        pthread_mutex_lock(&myMutex);
    
        while(var1InUse || var2InUse ) {
             pthread_cond_wait(&t1cond,&myMutex);
        }
        var1InUse=1,var2InUse=1;
    
        pthread_mutex_unlock(&myMutex);
    
        while(1){
    
            pthread_mutex_lock(&myMutex);
            /*
            some other code about adding and removing from linkedlist
            */
            var1InUse=0,var2InUse=0;
            pthread_cond_signal(&t2cond);
            pthread_cond_signal(&t3cond);
            pthread_mutex_unlock(&myMutex);
        }
        return NULL;
    }
    

    (I'm not entirely sure that the above is correct, because it's not entirely clear from the original code what the while(1) loop is supposed to do.)