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 if least_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 for least_max_value > 1. A specialization exists for least_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 released desired 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 from main()) causes all threads to be terminated before atexit() 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. Returns false 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. Returns false 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. Returns false 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.