0
votes
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;

void thread_1() {
    pthread_mutex_lock(&mutex); 
       some_cond = true;        
      pthread_cond_signal(&cv);    
    pthread_mutex_unlock(&mutex);       
}
void thread_2() {
    pthread_mutex_lock(&mutex);        
    while (!some_cond)              
        pthread_cond_wait(&cv, &mutex); 
    printf("test"); // After signaling from thread_1, does this get ran after?
    pthread_mutex_unlock(&mutex);       
}

Let's say that thread_2 calls pthread_cond_wait.

Thread_1 comes along then does pthread_cond_signal.

I understand that thread_2 will be blocked when pthread_cond_wait is called, and unlock its mutex. However, I am confuse on which line of code will run in thread_2 after thread_1 calls signal.

In thread_2 when its woken up, does it start from the beginning where thread_2 now has access to the mutex, then locks it, then checks the while condition again, and sees that its true now and prints test?

Or does thread_2 get access to its mutex, then locks it and then the print("test") is ran after (ignoring the while condition)?

4
Why not use a debugger to find out? Or you output some debug statements?Ulrich Eckhardt

4 Answers

1
votes

There is no specific line of code that is run in another thread when one calls pthread_cond_signal. If you want specific lines to be run in a specific order, you must put all those lines into the path of one thread.

When pthread_cond_signal is called, the other thread could be doing almost anything. One thing we know is that, because the signal call is inside the mutex, the other thread is not in the mutex. We can label the places where the other can be:

void thread_2() {
    // (A) Either here, or earlier.
 
    pthread_mutex_lock(&mutex);        
    while (!some_cond)              
        pthread_cond_wait(&cv, &mutex); // (B) Or here. 
    printf("test"); // After signaling from thread_1, does this get ran after?
    pthread_mutex_unlock(&mutex);  

    // (C) Or else here, or farther 
}

The other thread can be at C only if some_cond was already true. If some_cond is assumed false, we can forget about C.

If A is the case, the thread is either executing code before the pthread_mutex_lock (we can call that A1), or else it has hit the lock and is now waiting for the mutex (A2).

The thread which calls pthread_cond_signal owns the mutex, and continues to do so after making this call. So it's possible that the other thread is in A1, and proceeds to A2 (waiting on the mutex).

If the thread is in B: waiting on the condition variable, it's possible that the signal will wake it up. Before returning from pthread_cond_wait, it has to re-acquire the mutex, so it can get stuck waiting there. In any case, in the B state, the other thread cannot return from the pthread_cond_wait call until the first thread does the pthread_mutex_unlock.

It's possible that the other thread is in the A1 state (not yet reached the mutex), and the signaler completes everything: sets the variable, signals, and releases the mutex. Then the other thread will grab the mutex without waiting, see that the condition is true, and leave the mutex. The signaling is then irrelevant, since pthread_cond_wait is never called.

If you're doing programming with shared variables and explicit synchronization primitives like mutexes and conditions, you have to reason about all the cases which can happen: all the relevant states in which the other thread(s) can be.

0
votes

However, I am confuse on which line of code will run in thread_2 after thread_1 calls signal.

Actually, after the call of pthread_cond_signal from thread_1, nothing will happen, because thread_1 still have the mutex lock. The next instruction on thread_1 is pthread_mutex_unlock. The thread_2 will then stop blocking in pthread_cond_wait and atomically acquire the lock. The while condition will then check the condition, break and print "test".

0
votes

regarding:

void thread_1() {

and

void thread_2() {

Those are NOT valid signatures for thread functions! perhaps you meant:

void * thread_1( void *arg )

and

void * thread_2( void *arg )

Also, running off the end of a thread function is not valid. Suggest the last statement in each thread be:

pthread_exit( void );

There is no guarantee as to which thread runs first. If thread_2() runs first, then the mutex will be locked and thread_2() will be waiting, forever, for the pthread_condition(), but since thread_1() will be immediately blocked trying to obtain the mutex lock. NOTHING (more) will be executed in those threads.

in general, the function: pthread_wait() is called in the same part of the executable as called the function: pthread_create(). That halts the calling code until some thread exits (which, in the above scenario no thread will ever exit

0
votes

The several other examples are all good, but they also all seem to gloss over what I take to be the OP's key point of confusion.

I am confuse on which line of code will run in thread_2 after thread_1 calls signal.

There is no magic here. pthread_cond_wait() is a function, and it behaves like one. When its wait is over, and it has reacquired the mutex, it returns to its caller. Control proceeds normally from there, just as it would after any other function call returns.

In this particular case, the function call is the sole statement in the body of a while loop, so the next thing that happens after the call returns will be the while condition being reevaluated.

Note that pthread_cond_wait's caller can and should check the return value to catch and handle cases where it indicates that an error has occurred, just as should be done with other functions that indicate error conditions via their return values.