The thread calling pthread_cond_signal is re-grabbing the mutex before the signaled thread can be released.
The code below shows a simple example of the issue at hand. The main thread will hold the lock, create the worker thread, and then enter a loop that prints data as it comes in. It is signaled to run via a conditional variable.
The worker thread will enter a loop that generates data, grabs the lock, writes the data, and then signals the main thread.
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int data = 0;
void *thread(void *arg) {
int length = *(int *) arg;
for (int i = 0; i < length; i++) {
// Do some work
pthread_mutex_lock(&lock);
data = i;
fprintf(stdout, "Writing\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}
int main(int argc, const char *argv[]) {
pthread_t worker;
int length = 4;
pthread_mutex_lock(&lock);
pthread_create(&worker, 0, thread, &length);
for (int i = 0; i < length; i++) {
fprintf(stdout, "Waiting\n");
pthread_cond_wait(&cond, &lock);
fprintf(stdout, "read data: %d\n", data);
}
pthread_mutex_unlock(&lock);
pthread_join(worker, NULL);
return 0;
}
This will give the following output:
Waiting
Writing
Writing
Writing
Writing
read data: 3
Waiting
Expected behavior: Main thread holds the mutex and only releases it once its waiting. The worker thread will then write its data and signal the main thread. The main thread will immediately lock the mutex on signal, then read the data and go back to waiting, releasing the mutex. Meanwhile the worker thread will do its work and be waiting until the main thread is waiting again to write its data and signal it.
Instead, it appears that the worker thread is getting the mutex immediately after calling signal, rarely letting the main thread get access. If I put a sleep in the worker thread in place of the // Do some work
then it will give the expected output.