Recap: we were trying to implement the channel through // which producers and consumers can synchronize //example usage of the channel and our channel implementation typedef struct { pthread_mutex_t m; pthread_cond_t c; int *val; //can buffer one value }channel; channel c; void * sender_run(void *a) { int *n = (int *)malloc(sizeof(int)) *n = (int)a; chan_send(n); } void * receiver_run(void *) { int *v = chan_recv(); printf("recv %d\n", *v); free(v); } for (int i = 0; i < 5; i++) pthread_create(.., sender_run, (void *)i, ...); for (int i = 0; i < 5; i++) pthread_create(.., receiver_run, NULL, ...); void chan_send(int *v) { pthread_mutex_lock(&c.m); while (c.val != NULL) pthread_cond_wait(&c.c, &c.m); c.val = v; pthread_mutex_unlock(&c.m); } int * chan_recv() { //wait till c->val becomes not NULL pthread_mutex_lock(&c.m); int *v = c.val; c.val = NULL; pthread_cond_signal(&c.c); pthread_mutex_unlock(&c.m); return v; } Next how to get rid of the second wait in our channel example? void chan_send(int *v) { pthread_mutex_lock(&c.m); while (c.val != NULL) pthread_cond_wait(&c.c, &c.m); c.val = v; pthread_cond_signal(&c.c); pthread_mutex_unlock(&c.m); } int * chan_recv() { int *v; pthread_mutex_lock(&c.m); while (c.val == NULL) pthread_cond_wait(&c.c, &c.m); v = c.val; c.val = NULL; pthread_cond_signal(&c.c); phtread_mutex_unlock(&c.m); return v; } This code is correct but has spurious wakeups. See example: T1(recv) T2(recv) T3(send) ... cond_wait(&c.c, &c.m) cond_wait(&c.c., &c.m) c.val=v; signal unlock wakes up v=c.val c.val=NULL signal wakes up sees c.val=NULL, back to sleep on cond_wait In the above example that the wake up of T2 is not necessary. A better version that gets rid of spurious wakeups: void chan_send(int *v) { pthread_mutex_lock(&c.m); while (c.val != NULL) pthread_cond_wait(&c.c_null, &c.m); c.val = v; pthread_signal(&c.c_notnull); pthread_cond_unlock(&c.m); } int * chan_recv() { pthread_mutex_lock(&c.m); while (c->val == NULL) pthread_cond_wait(&c_notnull,&c.m); int *v = c.val; c.val = NULL; pthread_cond_signal(&c.c_null); pthread_mutex_unlock(&c.m); return v; } Let's do another example: barrier void * thread_run(void *arg) { printf("one\n"); barrier_wait(&b1); printf("two\n"); barrier_wait(&b2); printf("three\n"); } ... for (int i = 0; i < 10; i++) pthread_create(th[i], thread_run, NULL); typedef struct { pthread_mutex_t m; pthread_cond_t all_completed; int n; }barrier_t; //initialize the barrier to n void barrier_init(barrier_t *b, int n) { b->n = n; pthread_mutex_init(&b->m, NULL); pthread_cond_init(&b->all_completed, NULL); } //the first n-1 calls to barrier_wait block //after the n-th call to barrier_wait, all n calls unblock void barrier_wait(barrier_t *b) { pthread_mutex_lock(&b->m); b->n--; if (b->n == 0) { pthread_cond_broadcast(&b->all_completed); }else { while (b->n > 0) pthread_cond_wait(&b->all_completed, &b->m); } pthread_mutex_unlock(&b->m); }