Implementation of condition variables

c, gcc, linux, multithreading, pthreads

Solution

Basically your strategy looks ok, but you have one major danger, some undefined behavior, and a nit pick:

- your are not inspecting the return values of your POSIX functions. In particular `sem_wait` is interruptible so under heavy load or bad luck your thread will be woken up spuriously. You'd have to carefully catch all that

- none of your functions returns a value. If some user of the functions will decide to use the return values some day, this is undefined behavior. Carefully analyse the error codes that the condition functions are allowed to return and do just that.

- don't cast the return of `malloc` or `calloc`

Edit: Actually, you don't need `malloc`/`free` at all. A local variable would do as well.

Problem

To understand the code of pthread condition variables, I have written my own version. Does it look correct? I am using it in a program, its working, but working surprisingly much faster. Originally the program takes around 2.5 seconds and with my version of condition variables it takes only 0.8 seconds, and the output of the program is correct too. However, I'm not sure, if my implementation is correct. ``` struct cond_node_t { sem_t s; cond_node_t * next; }; struct cond_t { cond_node_t * q; // Linked List pthread_mutex_t qm; // Lock for the Linked List }; int my_pthread_cond_init( cond_t * cond ) { cond->q = NULL; pthread_mutex_init( &(cond->qm), NULL ); } int my_pthread_cond_wait( cond_t* cond, pthread_mutex_t* mutex ) { cond_node_t * self; pthread_mutex_lock(&(cond->qm)); self = (cond_node_t*)calloc( 1, sizeof(cond_node_t) ); self->next = cond->q; cond->q = self; sem_init( &self->s, 0, 0 ); pthread_mutex_unlock(&(cond->qm)); pthread_mutex_unlock(mutex); sem_wait( &self->s ); free( self ); // Free the node pthread_mutex_lock(mutex); } int my_pthread_cond_signal( cond_t * cond ) { pthread_mutex_lock(&(cond->qm)); if (cond->q != NULL) { sem_post(&(cond->q->s)); cond->q = cond->q->next; } pthread_mutex_unlock(&(cond->qm)); } int my_pthread_cond_broadcast( cond_t * cond ) { pthread_mutex_lock(&(cond->qm)); while ( cond->q != NULL) { sem_post( &(cond->q->s) ); cond->q = cond->q->next; } pthread_mutex_unlock(&(cond->qm)); } ```

Original source