Yastanub
Yastanub

Reputation: 1237

Does pthread_cond_wait lock the mutex und spurious wakeup

TL;DR

I have a homework where i need to implement thread synchronization. During implementation i was concerned if pthread_cond_wait() also locks mutex if it spuriously wakes up and not just if it successfully wakes up.

Task

The task is a worker/delivery problem where there are worker threads and management threads which provide orders for the workers. For this purpose there is an order list from which the workers get orders and the management thread deposits orders. The order list is a shared object and needs to be synchronized.

My solution so far

I thought for this problem i need a monitor for the list to protect it from accesses on emptiness or from deposits when its full.

void deposit_order(order_list* ol, order* o){
    pthread_mutex_lock(&(ol->mut_order_access));
    while(get_count(ol) >= MAX_ORDERS) {
        pthread_cond_wait(&(ol->cond_not_full), &(ol->mut_order_access));
    }

    ol->orders[ol->head] = o;
    ol->head = (ol->head+1)%MAX_ORDERS;
    ol->count++;
    
    pthread_cond_signal(&(ol->cond_not_empty));
    pthread_mutex_unlock(&(ol->mut_order_access));
}

order* get_order(order_list* ol) {
    pthread_mutex_lock(&(ol->mut_order_access));
    while(get_count(ol) <= 0) {
        pthread_cond_wait(&(ol->cond_not_empty), &(ol->mut_order_access));
    }
    order* o;
    
    o = ol->orders[ol->tail];
    ol->tail = (ol->tail+1)%MAX_ORDERS;
    ol->count--;
    
    pthread_cond_signal(&(ol->cond_not_full));
    pthread_mutex_unlock(&(ol->mut_order_access));
    return o;
}

I believe it is not that important what the structures contain since the topic is how to synchronize the access. Obviously the structure order_list holds a mutex and two condition variables to signal the other thread. So if a worker removes a task from the list, it signals "not empty" to the management thread so it can deposit an additional order. If the management deposits an order is signals "not empty" to the worker threads so one thread can remove an order from the list.

My Concerns

So far so good but now i think there is that one event where the above solution may be critical and that is a "spurious wakeup". From this thread i learned that a thread can not spuriously wakeup if the corresponding mutex namely mut_order_access is locked by another thread. But what if there is for example only one order in the list so that get_count(ol) >= MAX_ORDERS is not fulfilled and a thread spuriously wakes up from the wait, checks the condition and marks it as not true and jumps out of the loop. Then another thread receives the signal and wakes up normally locking the mutex after the previous thread is already in the critical area. So now both threads would be in the critical area which would be a failure.

Question

So the above could only happen if a thread does not lock the mutex when it spuriously wakes up so does it lock the mutex on spurious wakeup or not?

Upvotes: 1

Views: 470

Answers (2)

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215517

Your understanding of the conditions of spurious wakeup seems incorrect. Spurious wakeup has nothing to do with whether the mutex is locked by another thread. Unless you have a programming error (breaking the contracts of these functions, general memory corruption or other undefined behavior, etc.), pthread_cond_wait can never return without the mutex being held (locked) by the calling thread. In the event of a spurious wake, it still can't return until the mutex is re-acquired. Even in the event the waiter is cancelled with pthread_cancel, the cancellation cleanup handler cannot begin running until the mutex is re-acquired.

Upvotes: 4

David Schwartz
David Schwartz

Reputation: 182837

A function that might return with a mutex locked or unlocked and that gave you no way to tell the difference would be entirely unusable. How could you possibly know whether to unlock the mutex or not?

The pthread_cond_wait function provides an atomic "unlock and wait" operation. It always re-acquires the mutex before returning. Assuming you don't violate any of its pre-conditions, of course.

You can think of it as a three-step process:

  1. Atomic unlock and wait.
  2. Either another thread signals/broadcasts the condition or there's a spurious wakeup.
  3. Re-acquire the mutex

Only when all three steps are accomplished does pthread_cond_wait return. A spurious wakeup occurs when the wait ends without another thread sending a signal.

Upvotes: 3

Related Questions