Synchronization using Pthreads mutex and conditional variables in C -


i trying create 2 threads resembling taska , taskb. both taska , taskb kind of computation not interesting post. taska , taskb have executed 10 times in order cover whole array. taska has input aa , output bb. bb input of taskb. cc output of taskb. because bb written taska , read taskb need mutexes.

the behavior achieve when taska operates on i, taskb operates on i-1 in parallel, number of arrays processed. want avoid taskb wait taska finish every i.

the problem here have deadlock. threada , threadb represent taska , taskb. make easier removed computations , left synchronization instructions. deadlock caused because threada signals conditional variable cv[0] before threadb in state waits cv[0].

do know way remove deadlock without taska waiting taskb finish , vice versa. ideally when taska operates on array taskb should operate on array i-1.

/* includes */ #include <unistd.h>     /* symbolic constants */ #include <sys/types.h>  /* primitive system data types */  #include <errno.h>      /* errors */ #include <stdio.h>      /* input/output */ #include <stdlib.h>     /* general utilities */ #include <pthread.h>    /* posix threads */ #include <string.h>     /* string handling */ #include <semaphore.h>  /* semaphore */ #include <stdint.h>  #define array_size 2048*2400 #define debug //#define check_results  pthread_mutex_t mutex[10]; pthread_cond_t cv[10];  /* prototype thread routine */ void threada ( void *ptr ); void threadb ( void *ptr );   struct thread_arg {     uint32_t *in;     uint32_t *out;     uint32_t id;     };  int main() {      pthread_t ptha;     pthread_t pthb;    //memory allocation      uint32_t *aa = malloc(10*array_size*sizeof(uint32_t));      uint32_t *bb = malloc(10*array_size*sizeof(uint32_t));     uint32_t *cc = malloc(10*array_size*sizeof(uint32_t));      unsigned int j,i;      // thread arguments     struct thread_arg arguments[2];     arguments[0].in  = aa;     arguments[0].out = bb;     arguments[0].id  = 1;     arguments[1].in  = bb;     arguments[1].out = cc;     arguments[1].id  = 2;     //init arguments data     (j=0;j<10;j++)     {         (i=0;i<array_size;i++)         {             aa[j*array_size+i] = i;             bb[j*array_size+i] = 0;             cc[j*array_size+i] = 99 ;          }     }         //semaphore , conditional variables init     (i=0;i<10;i++){         pthread_mutex_init(&mutex[i], null);         pthread_cond_init (&cv[i], null);      }      pthread_create (&ptha, null, (void *) &threada, (void *) &arguments[0]);     pthread_create (&pthb, null, (void *) &threadb, (void *) &arguments[1]);      pthread_join(ptha, null);     pthread_join(pthb, null);      // destroy semaphores , cvs     (i=0;i<10;i++)     {         pthread_mutex_destroy(&mutex[i]);         pthread_cond_destroy(&cv[i]);      }            // checking results       exit(0); } /* main() */      void threada ( void *ptr ) {     int i;      struct thread_arg *arg = (struct thread_arg *) ptr;     (i=0;i<10;i++)     {         pthread_mutex_lock(&mutex[i]);         printf("ta: lock_m%d  \n",i);         pthread_cond_signal(&cv[i]);         printf("ta: sig_cv%d\n",i);         pthread_mutex_unlock(&mutex[i]);         printf("ta: unl_m%d\n",i);     }        pthread_exit(0); /* exit thread */ }     void threadb ( void *ptr ) {     int i;      struct thread_arg *arg = (struct thread_arg *) ptr;      (i=0;i<10;i++)     {         pthread_mutex_lock(&mutex[i]);         printf("tb: wait_cv%d\n",i,i);         pthread_cond_wait(&cv[i], &mutex[i]);         printf("tb cv%d_passed\n",i);         pthread_mutex_unlock(&mutex[i]);         printf("tb unl_m%d \n",i);     }    pthread_exit(null); } 

as whozcraig commented, condition variable needs paired condition on shared state, known predicate. mutex used protect shared state.

in example, shared state integer contains highest index of bb[] threada has produced. threadb waits number reach index reading. in design, need 1 mutex , 1 condition variable. globals be:

pthread_mutex_t mutex = pthread_mutex_initializer; pthread_cond_t cv = pthread_cond_initializer; int bb_ready = -1;  /* protected 'mutex' */ 

(using static pthread_*_initializer initialisers means don't need bother pthread_*_init() , pthread_*_destroy()).

the loop in threada be:

for (i=0;i<10;i++) {     /* process aa[i] bb[i] here */      /* mark bb[i] ready */     pthread_mutex_lock(&mutex);     printf("ta: lock_m%d  \n",i);     bb_ready = i;     pthread_cond_signal(&cv);     printf("ta: sig_cv%d\n",i);     pthread_mutex_unlock(&mutex);     printf("ta: unl_m%d\n",i); } 

..and in threadb:

for (i=0;i<10;i++) {     /* wait bb[i] ready */     pthread_mutex_lock(&mutex);     printf("tb: wait_cv%d\n",i);     while (bb_ready < i)         pthread_cond_wait(&cv, &mutex);     printf("tb cv%d_passed\n",i);     pthread_mutex_unlock(&mutex);     printf("tb unl_m%d \n",i);      /* process bb[i] cc[i] here */ } 

notice pthread_cond_signal() called whenever shared state has changed, allows other thread wake , re-check state, if it's waiting.

the waiting thread loops around, checking state , waiting on condition variable if state isn't ready yet.


Comments