How can I implement a binary semaphore using the POSIX counting semaphore API? I am using an unnamed semaphore and need to limit its count to 1. I believe I can't use a mutex because I need to be able to unlock from another thread.
-
Pass `1` as the `value` to `sem_init`? If you’re concerned that users could still increase the value by calling `sem_post` without first `sem_wait`ing, you could either wrap these calls into functions that guard against this, or [use a mutex + a condition variable](https://stackoverflow.com/a/7478825/1968) instead. – Konrad Rudolph Sep 04 '20 at 14:39
-
This is just the initial value of the semaphore. I can still, for example, call sem_post twice on a semaphore that is taken to make its count 2. – Sep 04 '20 at 14:42
-
Is this likely in your usage of the semaphore? In many cases `sem_post` and `sem_wait` are paired in such a way that no user would ever call `sem_post` without calling `sem_wait` first. Again, if this isn’t the case for you, refer to the linked alternative implementation. – Konrad Rudolph Sep 04 '20 at 14:46
-
1The implementation you linked to does not work. Suppose the semaphore value is 0. If call wait I will block the ```p->mutex``` but then when I call post (from another thread) I get blocked by it. – Sep 04 '20 at 14:48
-
@TertulianoMáximoAfonso: No, you won't. The mutex is not held during the condition wait. That's the whole point of the wait. – R.. GitHub STOP HELPING ICE Sep 04 '20 at 14:50
-
@R..GitHubSTOPHELPINGICE To be fair that implementation (incorrectly) does hold on to the mutex while waiting. It’s not a correct implementation, or am I seeing this wrong? – Konrad Rudolph Sep 04 '20 at 14:52
-
1@KonradRudolph `pthread_cond_wait(&p->cvar, &p->mutex);` unlocks the mutex while the condition variable is waiting. When the thread wakes up it grabs the mutex again. – Kevin Sep 04 '20 at 14:53
-
Ok. I got it. Thank you! – Sep 04 '20 at 14:54
-
1@KonradRudolph: You're seeing it wrong. `pthread_cond_wait` inherently unlocks the mutex and re-acquires it as part of finishing the wait This is not a convenience; it's an *inherent requirement* for a condition variable to fulfill its purpose. If the caller had to unlock before calling `pthread_cond_wait`, the state protected by the mutex would be checked without synchronization (data race) and could change between the check and the wait, thereby causing the waiter never to get woken. – R.. GitHub STOP HELPING ICE Sep 04 '20 at 14:54
-
@Kevin oooh. Of course! – Konrad Rudolph Sep 04 '20 at 14:55
-
This is possible using SysV semaphores. Have the signal sender uses `semctl` with a `cmd` of `SETVAL` to set the semaphore's value to `1`. Have the signal receiver use a standard down/wait operation (`semop` with a `sem_op` of `-1`). – ikegami Sep 04 '20 at 15:08
1 Answers
If you actually want a semaphore that "absorbs" multiple posts without allowing multiple waits to succeed, and especially if you want to be strict about that, POSIX semaphores are not a good underlying promitive to use to implement it. The right set of primitives to implement it on top of is a mutex, a condition variable, and a bool
protected by the mutex. When changing the bool
from 0 to 1, you signal the condition variable.
With that said, what you're asking for is something of a smell; it inherently has ambiguous orderings. For example if threads A and B both post the semaphore one after another, and threads X and Y are both just starting to wait, it's possible with your non-counting semaphore that either both waits succeed or that only one does, depending on the order of execution: ABXY or AXBY (or other comparable permutation). Thus, the pattern is likely erroneous unless either there's only one thread that could possibly psot at any given time (in which case, why would it post more than once? maybe this is a non-issue) or ability to post is controlled by holding some sort of lock (again, in which case why would it post more than once?). So if you don't have a design flaw here, it's likely that just using a counting semaphore but not posting it more than once gives the behavior you want.
If that's not the case, then there's probably some other data associated with the semaphore that's not properly synchronized, and you're trying to use the semaphore like a condition variable for it. If that's the case, just put a proper mutex and condition variable around it and use them, and forget the semaphore.
One comment for addressing your specific situation:
I believe I can't use a mutex because I need to be able to unlock from another thread.
This becomes a non-issue if you use a combination of mutex and condition variable, because you don't keep the mutex locked while working. Instead, the fact that the combined system is in-use is part of the state protected by the mutex (e.g. the above-mentioned bool
) and any thread that can obtain the mutex can change it (to return it to a released state).

- 208,859
- 35
- 376
- 711
-
What I want is not a smell. I want something like FreeRTOS binary semaphore: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html – Sep 04 '20 at 14:50
-
1@TertulianoMáximoAfonso: Smell doesn't mean it's inherently wrong, just that it's a clue that something might be seriously wrong and that it requires further checking of the particular usage to determine if that's the case. – R.. GitHub STOP HELPING ICE Sep 04 '20 at 14:55
-
Re "*What I want is not a smell.*", The article to which you linked identified exactly the same problem as R did: It only works if you have a single writer and a single reader. That's a very serious limitation, so it smells, or raises red flags, when someone says this is what they want. It doesn't mean that it's never useful. – ikegami Sep 04 '20 at 14:58