carb::cpp::counting_semaphore
Defined in carb/cpp/Semaphore.h
-
template<ptrdiff_t least_max_value = detail::kSemaphoreValueMax>
class counting_semaphore C++20-compatible counting semaphore class.
A counting_semaphore is a lightweight synchronization primitive that can control access to a shared resource. Unlike a mutex, a counting_semaphore allows more than one concurrent access to the same resource, for at least
least_max_value
concurrent accessors. The program is ill-formed ifleast_max_value
is negative.This is a C++14-compatible implementation of std::counting_semaphore from C++20 draft spec dated 11/13/2019.
- Thread Safety
This class is thread-safe. However, attempting to destruct before all threads have returned from any function (especially the wait functions) is malformed and will lead to undefined behavior.
Note
sizeof(counting_semaphore)
is 8 bytes forleast_max_value > 1
. A specialization exists forleast_max_value == 1
where the size is only 1 byte, also known as binary_semaphore.- Template Parameters
least_max_value – The maximum count value that this semaphore can reach. This indicates the number of threads or callers that can simultaneously successfully acquire this semaphore. May not be less than or equal to zero.
Public Functions
-
inline explicit constexpr counting_semaphore(ptrdiff_t desired) noexcept
Constructor: initializes a new semaphore object with a given count.
- Parameters
desired – [in] The initial count value for the semaphore. This must be a positive value or zero. If set to zero, the semaphore will be ‘unowned’ on creation. If set to any other value, the semaphore will only be able to be acquired by at most least_max_value minus
desired
other threads or callers until it is releaseddesired
times.
-
inline ~counting_semaphore() noexcept
Destructor.
On Linux, performs a
CARB_CHECK
to verify that no waiters are present when*this
is destroyed.Note
On Windows,
ExitProcess()
(or returning frommain()
) causes all threads to be terminated beforeatexit()
registered functions are called (and static objects are cleaned up). This has the unpleasant side effect of potentially terminating threads that are waiting on a semaphore and will never get the chance to clean up their waiting count. Therefore, this check is linux only.
-
inline void release(ptrdiff_t update = 1) noexcept
Releases references on this semaphore and potentially wakes another waiting thread.
Remark
This releases zero or more references on this semaphore. If a reference is released, another waiting thread could potentially be woken and acquire this semaphore again.
- Thread Safety
This call is thread safe.
- Parameters
update – [in] The number of references to atomically increment this semaphore’s counter by. This number of waiting threads will be woken as a result.
- Returns
No return value.
-
inline void acquire() noexcept
Acquires a reference to this semaphore.
Remark
This blocks until a reference to this semaphore can be successfully acquired. This is done by atomically decrementing the semaphore’s counter if it is greater than zero. If the counter is zero, this will block until the counter is greater than zero. The counter is incremented by calling release().
- Thread Safety
This call is thread safe.
- Returns
No return value.
-
inline bool try_acquire() noexcept
Attempts to acquire a reference to this semaphore.
- Thread Safety
This call is thread safe.
- Returns
true
if the semaphore’s counter was greater than zero and it was successfully atomically decremented. Returnsfalse
if the counter was zero and the semaphore could not be acquired. This will never block even if the semaphore could not be acquired.
-
template<class Rep, class Period>
inline bool try_acquire_for(const std::chrono::duration<Rep, Period> &duration) noexcept Attempts to acquire a reference to this semaphore for a specified relative time.
- Thread Safety
This call is thread safe.
- Template Parameters
Rep – The representation primitive type for the duration value.
Period – The duration’s time scale value (ie: milliseconds, seconds, etc).
- Parameters
duration – [in] The amount of time to try to acquire this semaphore for. This is specified as a duration relative to the call time.
- Returns
true
if the semaphore’s counter was greater than zero and it was successfully atomically decremented within the specified time limit. Returnsfalse
if the counter was zero and the semaphore could not be acquired within the time limit. This will only block for up to approximately the specified time limit.
-
template<class Clock, class Duration>
inline bool try_acquire_until(const std::chrono::time_point<Clock, Duration> &time_point) noexcept Attempts to acquire a reference to this semaphore until a specified absolute time.
- Thread Safety
This call is thread safe.
- Template Parameters
Clock – The clock to use as a time source to compare the time limit to.
Duration – The duration type associated with the specified clock.
- Parameters
time_point – [in] The absolute time to try to acquire this semaphore for. This is specified as a time point from the given clock Clock.
- Returns
true
if the semaphore’s counter was greater than zero and it was successfully atomically decremented before the specified time limit. Returnsfalse
if the counter was zero and the semaphore could not be acquired before the time limit. This will only block up until approximately the specified time limit.
Public Static Functions
-
static inline constexpr ptrdiff_t max() noexcept
Retrieves the maximum count value this semaphore can reach.
- Thread Safety
This call is thread safe.
- Returns
The maximum count value for this semaphore. This will never be zero.