2

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.

11
  • 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_waiting, you could either wrap these calls into functions that guard against this, or use a mutex + a condition variable instead. Commented Sep 4, 2020 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. Commented Sep 4, 2020 at 14:42
  • 1
    The 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. Commented Sep 4, 2020 at 14:48
  • 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. Commented Sep 4, 2020 at 14:53
  • 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. Commented Sep 4, 2020 at 14:54

1 Answer 1

3

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).

Sign up to request clarification or add additional context in comments.

3 Comments

What I want is not a smell. I want something like FreeRTOS binary semaphore: freertos.org/Embedded-RTOS-Binary-Semaphores.html
@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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.