Conditional variable versus semaphore

When should a semaphore be used and when should a conditional variable (CondVar) be used?

+66
multithreading synchronization operating-system semaphore mutual-exclusion
Aug 18 '10 at 14:19
source share
5 answers

Locks are used for mutual exclusion. If you want a piece of code to be atomic, put a lock around it. Theoretically, you can use a binary semaphore for this, but this is a special case.

Semaphores and variable conditions are built on top of the mutual exclusion provided by locks and are used to provide synchronous access to shared resources. They can be used for similar purposes.

Typically, a condition variable is used to avoid waiting for a wait (repeating a loop when checking the status), waiting for a resource to become available. For example, if you have a thread (or several threads) that cannot continue until the queue is empty, the wait approach will simply do something like:

//pseudocode while(!queue.empty()) { sleep(1); } 

The problem is that you are losing processor time when this thread re-checks the status. Why is there instead a synchronization variable that can be signaled to tell the stream that the resource is available?

 //pseudocode syncVar.lock.acquire(); while(!queue.empty()) { syncVar.wait(); } //do stuff with queue syncVar.lock.release(); 

Presumably, you will have a thread elsewhere that pulls things from the queue. When the queue is empty, it can call syncVar.signal() to wake up a random stream that falls asleep in syncVar.wait() (or the signalAll() or broadcast() method is usually used to wake up all waiting threads).

I usually use synchronization variables such as this when I have one or more threads waiting in one particular state (for example, so that the queue is empty).

Semaphores can be used in a similar way, but I think they are better used when you have a shared resource that can be accessed and inaccessible based on some integer number of things available. Semaphores are good for producer / consumer situations where producers allocate resources and consumers consume them.

Think about whether you have a soda vending machine. There is only one soda machine, and this is a common resource. You have one stream, which is the seller (manufacturer), which is responsible for storing spare parts of the machine and N flows, which are buyers (consumers) who want to get soda from the machine. The amount of soda in the machine is the integer value that will drive our semaphore.

Each consumer (consumer) thread that enters the soda machine calls the down() semaphore method to receive the soda. This will bring the soda from the machine and reduce the number of soda available by 1. If there is soda available, the code will simply continue to work after the down() instruction without any problems. If no soda is available, the thread will sleep here, waiting for a notification when the soda will be available again (when there will be more carbonated drinks in the machine).

The supplier (manufacturer) thread will essentially wait until the soda machine is empty. The supplier is notified when the last soda is taken from the machine (and one or more consumers are potentially waiting for the soda to be released). The supplier will replenish the soda machine using the up() semaphore method, the available number of soda will increase each time, and thus, pending consumer flows will be notified that more soda is available.

The wait() and signal() methods of the synchronization variable are usually hidden in the semaphore down() and up() operations.

Of course, there is overlap between these two options. There are many scenarios in which a semaphore or condition variable (or a set of condition variables) can serve your purpose. Both semaphores and condition variables are associated with a lock object, which they use to maintain mutual exclusion, but then they provide additional functionality on top of the lock to synchronize thread execution. It is basically up to you to figure out which one makes the most sense for your situation.

This is not necessarily the most technical description, but how it makes sense in my head.

+136
Aug 18 '10 at 16:35
source share

Show that under the hood.

A conditional variable is, in fact, a wait queue that supports blocking-waiting and waking operations, that is, you can put a stream in the wait queue and set its state to BLOCK and get the stream from it and set its state to READY.

Note that two other elements are required to use a conditional variable:

  • condition (usually implemented by checking a flag or counter)
  • mutex that protects the condition

Then the protocol becomes,

  • get mutex
  • check condition
  • lock and release mutex, if condition is true, else release mutex

A semaphore is essentially a counter + mutex + wait queue. And it can be used as without external dependencies. You can use it either as a mutex or as a conditional variable.

Therefore, a semaphore can be considered as a more complex structure than a conditional variable, while the latter is easier and more flexible.

+20
Nov 24 '15 at 20:30
source share

Semaphores can be used to provide exclusive access to variables, but they are intended to be used for synchronization. Mutexes, on the other hand, have semantics that are strictly related to mutual exclusion: only the process that blocked the resource allows it to be unlocked.

Unfortunately, you cannot implement synchronization with mutexes, so we have variable conditions. Also note that with state variables, you can unlock all pending streams at the same time using broadcast unlock. This cannot be done with semaphores.

+13
Aug 18 '10 at 16:44
source share

semaphore and variable conditions are very similar and are used mainly for the same purpose. However, there are minor differences that may make it preferable. For example, to implement barrier synchronization, you cannot use a semaphore. But the condition variable is perfect.

Barrier synchronization is when you want all your threads to wait until everyone reaches a certain part of the stream function. this can be done using a static variable, which is initially the value of all threads decreasing by each thread when it reaches this barrier. this would mean that we want each thread to sleep until the last one arrives. The semaphore will do the opposite! with a semaphore, each thread will continue to work, and the last thread (which sets the semaphore to 0) will go into sleep mode.

the condition variable, on the other hand, is ideal. when each thread hits the barrier, we check to see if our static counter is zero. if not, we set the thread to standby with the wait function of the condition variable. when the last thread reaches the barrier, the counter value will be reduced to zero, and this last thread will call the conditional value signal function, which will awaken all other threads!

+2
Dec 22 '16 at 3:43
source share

I commit file state variables during monitor synchronization. I usually saw semaphores and monitors as two different styles of synchronization. There are differences between them regarding how much state data is saved and how you want to model the code - but there really are no problems that can be solved by one and not the other.

I tend to code the shape of the monitor; in most of the languages ​​I work in, it comes down to mutexes, state variables, and some support state variables. But semaphores would also do the job.

+1
Aug 18 '10 at 16:44
source share



All Articles