0

I'm looking at the following snippets:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cvar;
char buf[25];
void*thread_f(void *);

int main(){

    pthread_t thr; 
    pthread_cond_init(&cvar,NULL);
    pthread_mutex_lock(&mtx);
    pthread_create(&thr,NULL,thread_f,NULL);
    pthread_cond_wait(&cvar,&mtx);
    pthread_mutex_unlock(&mtx);
    ...join and destroy thread...
}

and thread_f:

void* thread_f(void* argp){

    pthread_mutex_lock(&mtx);
    strcpy(buf,"test");
    pthread_cond_signal(&cvar);
    pthread_mutex_unlock(&mtx); //why?
    pthread_exit(NULL);
}

My understanding of the above code is, that main grabs the lock, creates the thread and runs thread_f which blocks. Then, main signals the wait on the condition variable cvar and unlocks the mutex. Then, thread_f unblocks, strcpys and signals cvar to wake up. Then, both main and thread_f unlock the mutex.

Is this the actual behaviour, or am I missing something somewhere? If it's the actual behaviour, isn't unlocking the already unlocked mutex UB, therefore should one of he mutex unlocks in the end be removed?

Thanks.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
Pol
  • 185
  • 9
  • 2
    upon successful return, `pthread_cond_wait` locks the mutex, so `mtx` is locked when `main` calls `pthread_mutex_unlock` (assuming a successful return, which is not checked). So essentially `pthread_cond_wait` has to wait for a signal _and_ the ability to acquire the mutex, and it can't acquire `mtx` until `thread_f` unlocks it. Here's a shameless plug for [my answer](https://stackoverflow.com/questions/72295835/what-happens-when-a-thread-calls-pthread-mutex-unlock-on-an-already-unlocked-mut/72296388#72296388) to a nearly identical question. – yano May 31 '22 at 15:41

2 Answers2

1

The pthread_cond_wait() in the main thread unlocks the mutex and waits for the condition to be signalled — and relocks the mutex before returning.

The child thread is able to lock the mutex, manipulate the buffer, signal the condition and then unlock the mutex, letting the main thread reacquire the lock.

Consequently, the code is well-behaved — give or take the need to worry about 'spurious wakeups' in more general situations with multiple child threads. I don't think you can get a spurious wakeup here.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

What this code is doing is valid.

When the thread calls pthread_cond_signal it doesn't immediately cause the main thread to grab the mutex, but wakes up the main thread so it can attempt to lock it. Then once the thread releases the mutex, the main thread is able to lock it and return from pthread_cond_wait.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    Technically, what the code is doing is **not valid** because of [spurious wakeup](https://en.wikipedia.org/wiki/Spurious_wakeup). `pthread_cond_wait` should always be called in a loop, and the loop should only exit when the condition has actually been signaled. – user3386109 May 31 '22 at 15:49