What are the pros / cons of using pthread_cond_wait
or using a semaphore ? I am waiting for a state change like this :
pthread_mutex_lock(&cam->video_lock); while(cam->status == WAIT_DISPLAY) { pthread_cond_wait(&cam->video_cond, &cam->video_lock); } pthread_mutex_unlock(&cam->video_lock);
Using a properly initialised semaphore, I think I could do it like this :
while(cam->status == WAIT_DISPLAY) { sem_wait(&some_semaphore); }
What are the pros and cons of each method ?
The pthread_cond_wait() function blocks the calling thread, waiting for the condition specified by cond to be signaled or broadcast to. When pthread_cond_wait() is called, the calling thread must have mutex locked. The pthread_cond_wait() function atomically unlocks mutex and performs the wait for the condition.
A Mutex is different than a semaphore as it is a locking mechanism while a semaphore is a signalling mechanism. A binary semaphore can be used as a Mutex but a Mutex can never be used as a semaphore.
The pthread_cond_wait() routine always returns with the mutex locked and owned by the calling thread, even when returning an error. This function blocks until the condition is signaled. The function atomically releases the associated mutex lock before blocking, and atomically acquires the mutex again before returning.
A semaphore is suited cleanly to a producer-consumer model, although it has other uses. Your program logic is responsible for ensuring that the right number of posts are made for the number of waits. If you post a semaphore and nobody is waiting on it yet, then when they do wait they continue immediately. If your problem is such that it can be explained in terms of the count value of a semaphore, then it should be easy to solve with a semaphore.
A condition variable is a bit more forgiving in some respects. You can for example use cond_broadcast to wake up all waiters, without the producer knowing how many there are. And if you cond_signal a condvar with nobody waiting on it then nothing happens. This is good if you don't know whether there's going to be a listener interested. It is also why the listener should always check the state with the mutex held before waiting - if they don't then they can miss a signal and not wake up until the next one (which could be never).
So a condition variable is suitable for notifying interested parties that state has changed: you acquire the mutex, change the state, signal (or broadcast) the condvar and release the mutex. If this describes your problem you're in condvar territory. If different listeners are interested in different states you can just broadcast and they'll each in turn wake up, figure out whether they've found the state they want, and if not wait again.
It's very gnarly indeed to attempt this sort of thing with a mutex and a semaphore. The problem comes when you want to take the mutex, check some state, then wait on the semaphore for changes. Unless you can atomically release the mutex and wait on the semaphore (which in pthreads you can't), you end up waiting on the semaphore while holding the mutex. This blocks the mutex, meaning that others can't take it to make the change you care about. So you will be tempted to add another mutex in a way which depends on your specific requirements. And maybe another semaphore. The result is generally incorrect code with harmful race conditions.
Condition variables escape this problem, because calling cond_wait automatically releases the mutex, freeing it for use by others. The mutex is regained before cond_wait returns.
IIRC it is possible to implement a kind of condvar using only semaphores, but if the mutex you're implementing to go with the condvar is required to have trylock, then it's a serious head-scratcher, and timed waits are out. Not recommended. So don't assume that anything you can do with a condvar can be done with semaphores. Plus of course mutexes can have nice behaviours that semaphores lack, principally priority-inversion avoidance.
Conditionals let you do some things that semaphores won't.
For example, suppose you have some code which requires a mutex, called m
. It however needs to wait until some other thread has finish their task, so it waits on a semaphore called s
. Now any thread which needs m
is blocked from running, even though the thread which has m
is waiting on s
. These kind of situations can be resolved using conditionals. When you wait on a conditional, the mutex currently held is released, so other threads can acquire the mutex. So back to our example, and suppose conditional c
was used instead of s
. Our thread now acquires m
, and then conditional waits on c
. This releases m
so other threads can proceed. When c
becomes available, m
is reacquired, and our original thread can continue merrily along its way.
Conditional variables also allows you to let all threads waiting on a conditional variable to proceed via pthread_cond_broadcast
. Additionally it also allows you to perform a timed wait so you don't end up waiting forever.
Of course, sometimes you don't need conditional variables, so depending on your requirements, one or the other may be better.
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