Signal Before Wait

A hand-rolled join. There is no state variable, only the condition variable.

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  c = PTHREAD_COND_INITIALIZER;

void thr_exit(void) {                 // child calls this last
    pthread_mutex_lock(&m);
    pthread_cond_signal(&c);
    pthread_mutex_unlock(&m);
}

void thr_join(void) {                 // parent calls this
    pthread_mutex_lock(&m);
    pthread_cond_wait(&c, &m);
    pthread_mutex_unlock(&m);
}

On a developer laptop this passes every time. On a loaded CI box it hangs about once in fifty runs. What is the schedule that hangs?

A

A spurious wakeup returned the parent from pthread_cond_wait before the child had signaled, so the parent proceeded on unfinished state.

B

The child ran to completion and signaled before the parent reached pthread_cond_wait. A signal with no waiter is discarded, so the parent then waits for a wakeup that will never be sent.

C

The child signaled while still holding m, so the parent could not reacquire m in order to return from pthread_cond_wait.

D

The parent held m when it called pthread_cond_wait, so the child blocked forever in pthread_mutex_lock.