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
Post a Comment