So I have searched high and low on stack overflow and other resources but I am unable to understand a few things with regards to the aforementioned functions. Specifically,
1)When pthread_cond_timedwait() returns because a timer value has run out, how does it automatically re-acquire the mutex. The mutex could potentially be locked elsewhere. For instance, in say a producer-consumer queue, the consumer could be waiting using the timedwait() variant. From explanations I have read, it appears that the mutex will automatically be re-acquired when the thread wakes up. This baffles me? Or is it that it will wake up after the timer runs out and then check the predicate and lock again. That makes no sense?
2)When a bunch of threads have acquired a mutex and are now all waiting on a simple pthread_cond_wait(), what will happen if another thread issues a pthread_cond_broadcast(). Will each of the threads (as determined by the scheduler) wake up one by one, acquire the mutex in sequence and then each of them proceed? Or will only one thread of the entire list of threads wake up. I would assume that the latter of the two behaviors would be possible using pthread_cond_signal() as well. Also, if the previous approach is the right behavior, then we can assume that some other thread might end up calling wait() on the variable somewhere else. Would that then put all these other waiting threads back into a blocked state and waiting for a signal. Or would each of them continue to wake up and make progress one by one?
(1) pthread_cond_timedwait()
A short (and shallow) explanation how it works.
1) The mutex, associated with the pthread_cond_timewait() should be locked before a call to the function. It is your responsibility to do it. Otherwise, the function behavior is undefined.
2) When your program transfers its control to the function, the function ATOMICALLY releases the associated mutex, giving other threads a chance to acquire it. When you are waiting, the mutex is unlocked. It is the function responsibility to unlock it. If the function implementation could not do it, only one single thread would deal with the associated mutex.
3) When the function returns, either as a result of timeout or as a result of receiving a signal, the function ATOMICALLY locks the mutex back. It is the function responsibility to lock the mutex.
4) Now the mutex should be unlocked again by you.
The word "atomically" in the explanation means, that the function itself is thread safe.
(2) pthread_cond_broadcast()
Signaling with pthread_cond_broadcast() causes to all waiting threads to wake up and start processing one by one. Signaling with pthread_cond_signal() causes only one single thread to wake up. To "feel" the concept you may play with the following code that illustrates the idea. Replace the pthread_cons_signal with the pthread_cond_brodcast. Take into consideration that the program will never terminate when pthread_cons_signal is used: only one waiter thread gets the signal and escapes from the wait loop.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int value = 0;
void* waiter(void* arg)
{
int* tid = (int*)arg;
printf("waiter started %d\n", *tid);
pthread_mutex_lock(&mutex);
while(value == 0)
{
pthread_cond_wait(&cond, &mutex);
}
sleep(10);
printf("waiter %d releases\n", *tid);
pthread_mutex_unlock(&mutex);
}
void* notifier(void* arg)
{
sleep(2);
pthread_mutex_lock(&mutex);
value = 1;
//pthread_cond_broadcast(&cond);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
int main(void)
{
pthread_t w1; // waiter
int tid1=1;
pthread_t w2; // waiter
int tid2=2;
pthread_t n1; // notifier
pthread_create(&w1, NULL, waiter, &tid1);
pthread_create(&w2, NULL, waiter, &tid2);
pthread_create(&n1, NULL, notifier, NULL);
pthread_join(w1, NULL);
pthread_join(w2, NULL);
pthread_join(n1, NULL);
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With