Looking in cppreference, it seems to imply a std::binary_semaphore
may be more efficient than a std::mutex
.
Is there any reason not to use a std::binary_semaphore
initialized to 1
instead of a std::mutex
?
There are differences between a std::binary_semaphore
and a std::mutex
which are mentioned in the cppreference documentation (under the Notes section):
Unlike
std::mutex
acounting_semaphore
is not tied to threads of execution - acquiring a semaphore can occur on a different thread than releasing the semaphore, for example. All operations oncounting_semaphore
can be performed concurrently and without any relation to specific threads of execution, with the exception of the destructor which cannot be performed concurrently but can be performed on a different thread.Semaphores are also often used for the semantics of signaling/notifying rather than mutual exclusion, by initializing the semaphore with 0 and thus blocking the receiver(s) that try to
acquire()
, until the notifier "signals" by invokingrelease(n)
. In this respect semaphores can be considered alternatives tostd::condition_variable
s, often with better performance.
So I would say there are some reasons to use std::mutex
:
In addition - as @MatthieuM. commented below, mutex implementations might be able to offer a performance advantage over a semaphore, e.g. - Futex implementation on Linux.
In summary:
These are two separate programming constructs.
They do have some potential functional overlap, but this is something which quite common (e.g. you can do with a struct
everything you can do with a class
. But they do have some differences and might be used in difference context).
This old post is from some years before C++20 was introduced (and std::binary_semaphore
added), but it contains some additional relevant information.
A side note:
As @interjay commented above, cppreference does not mention the efficiency of std::binary_semaphore
v.s. std::mutex
, but rather that it may be more efficient than std::counting_semaphore
:
Implementations may implement binary_semaphore more efficiently than the default implementation of std::counting_semaphore.
There is no reason to assume a std::binary_semaphore
will be more efficient for implementing mutual exclusion than a std::mutex
. As has been pointed out in the comments, cppreference merely hints at a potential performance difference between the counted and binary semaphore.
In general, mutex and semaphore target different use cases: A semaphore is for signalling, a mutex is for mutual exclusion. Mutual exclusion means you want to make sure that multiple threads cannot execute certain critical sections of code at the same time. std::mutex
is the only synchronization facility in the standard library for this use case. The semaphore on the other hand targets the use case where one thread causes the program state to change and now wants to inform another thread of that change. There are multiple similar facilities in the standard library that target signalling use cases, for example std::condition_variable
.
This is also the reason why semaphores do not require to be acquired and released on the same thread, unlike mutexes where unlocking a mutex that is held by another thread results in undefined behavior.
You should avoid using a signalling primitive for implementing mutual exclusion. Even though this can in theory be done, it is very easy to do it subtly wrong and likely to be less efficient than a dedicated mutual exclusion algorithm.
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