[thread.sema] # 32 Concurrency support library [[thread]](./#thread) ## 32.8 Semaphore [thread.sema] ### [32.8.1](#general) General [[thread.sema.general]](thread.sema.general) [1](#general-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10435) Semaphores are lightweight synchronization primitives used to constrain concurrent access to a shared resource[.](#general-1.sentence-1) They are widely used to implement other synchronization primitives and, whenever both are applicable, can be more efficient than condition variables[.](#general-1.sentence-2) [2](#general-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10441) A counting semaphore is a semaphore object that models a non-negative resource count[.](#general-2.sentence-1) A binary semaphore is a semaphore object that has only two states[.](#general-2.sentence-2) A binary semaphore should be more efficient than the default implementation of a counting semaphore with a unit resource count[.](#general-2.sentence-3) ### [32.8.2](#semaphore.syn) Header synopsis [[semaphore.syn]](semaphore.syn) [🔗](#header:%3csemaphore%3e) namespace std {// [[thread.sema.cnt]](#cnt "32.8.3 Class template counting_­semaphore"), class template counting_semaphoretemplateclass counting_semaphore; using [binary_semaphore](#lib:binary_semaphore "32.8.2 Header synopsis [semaphore.syn]") = counting_semaphore<1>;} ### [32.8.3](#cnt) Class template counting_semaphore [[thread.sema.cnt]](thread.sema.cnt) namespace std {templateclass counting_semaphore {public:static constexpr ptrdiff_t max() noexcept; constexpr explicit counting_semaphore(ptrdiff_t desired); ~counting_semaphore(); counting_semaphore(const counting_semaphore&) = delete; counting_semaphore& operator=(const counting_semaphore&) = delete; void release(ptrdiff_t update = 1); void acquire(); bool try_acquire() noexcept; templatebool try_acquire_for(const chrono::duration& rel_time); templatebool try_acquire_until(const chrono::time_point& abs_time); private: ptrdiff_t counter; // *exposition only*};} [1](#cnt-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10490) Class template counting_semaphore maintains an internal counter that is initialized when the semaphore is created[.](#cnt-1.sentence-1) The counter is decremented when a thread acquires the semaphore, and is incremented when a thread releases the semaphore[.](#cnt-1.sentence-2) If a thread tries to acquire the semaphore when the counter is zero, the thread will block until another thread increments the counter by releasing the semaphore[.](#cnt-1.sentence-3) [2](#cnt-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10500) least_max_value shall be non-negative; otherwise the program is ill-formed[.](#cnt-2.sentence-1) [3](#cnt-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10503) Concurrent invocations of the member functions of counting_semaphore, other than its destructor, do not introduce data races[.](#cnt-3.sentence-1) [🔗](#lib:max,counting_semaphore) `static constexpr ptrdiff_t max() noexcept; ` [4](#cnt-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10513) *Returns*: The maximum value of counter[.](#cnt-4.sentence-1) This value is greater than or equal to least_max_value[.](#cnt-4.sentence-2) [🔗](#lib:counting_semaphore,constructor) `constexpr explicit counting_semaphore(ptrdiff_t desired); ` [5](#cnt-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10525) *Preconditions*: desired >= 0 is true, anddesired <= max() is true[.](#cnt-5.sentence-1) [6](#cnt-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10530) *Effects*: Initializes counter with desired[.](#cnt-6.sentence-1) [7](#cnt-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10534) *Throws*: Nothing[.](#cnt-7.sentence-1) [🔗](#lib:release,counting_semaphore) `void release(ptrdiff_t update = 1); ` [8](#cnt-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10545) *Preconditions*: update >= 0 is true, andupdate <= max() - counter is true[.](#cnt-8.sentence-1) [9](#cnt-9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10550) *Effects*: Atomically execute counter += update[.](#cnt-9.sentence-1) Then, unblocks any threads that are waiting for counter to be greater than zero[.](#cnt-9.sentence-2) [10](#cnt-10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10556) *Synchronization*: Strongly happens before invocations of try_acquire that observe the result of the effects[.](#cnt-10.sentence-1) [11](#cnt-11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10561) *Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#cnt-11.sentence-1) [12](#cnt-12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10565) *Error conditions*: Any of the error conditions allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2 Mutex types"))[.](#cnt-12.sentence-1) [🔗](#lib:try_acquire,counting_semaphore) `bool try_acquire() noexcept; ` [13](#cnt-13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10577) *Effects*: Attempts to atomically decrement counter if it is positive, without blocking[.](#cnt-13.sentence-1) If counter is not decremented, there is no effect andtry_acquire immediately returns[.](#cnt-13.sentence-2) An implementation may fail to decrement counter even if it is positive[.](#cnt-13.sentence-3) [*Note [1](#cnt-note-1)*: This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange ([[atomics]](atomics "32.5 Atomic operations"))[.](#cnt-13.sentence-4) — *end note*] An implementation should ensure that try_acquire does not consistently return false in the absence of contending semaphore operations[.](#cnt-13.sentence-5) [14](#cnt-14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10594) *Returns*: true if counter was decremented, otherwise false[.](#cnt-14.sentence-1) [🔗](#lib:acquire,counting_semaphore) `void acquire(); ` [15](#cnt-15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10605) *Effects*: Repeatedly performs the following steps, in order: - [(15.1)](#cnt-15.1) Evaluates try_acquire()[.](#cnt-15.1.sentence-1) If the result is true, returns[.](#cnt-15.1.sentence-2) - [(15.2)](#cnt-15.2) Blocks on *this until counter is greater than zero[.](#cnt-15.2.sentence-1) [16](#cnt-16) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10615) *Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#cnt-16.sentence-1) [17](#cnt-17) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10619) *Error conditions*: Any of the error conditions allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2 Mutex types"))[.](#cnt-17.sentence-1) [🔗](#lib:try_acquire_for,counting_semaphore) `template bool try_acquire_for(const chrono::duration& rel_time); template bool try_acquire_until(const chrono::time_point& abs_time); ` [18](#cnt-18) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10635) *Effects*: Repeatedly performs the following steps, in order: - [(18.1)](#cnt-18.1) Evaluates try_acquire()[.](#cnt-18.1.sentence-1) If the result is true, returns true[.](#cnt-18.1.sentence-2) - [(18.2)](#cnt-18.2) Blocks on *this until counter is greater than zero or until the timeout expires[.](#cnt-18.2.sentence-1) If it is unblocked by the timeout expiring, returns false[.](#cnt-18.2.sentence-2) The timeout expires ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) when the current time is after abs_time (for try_acquire_until) or when at least rel_time has passed from the start of the function (for try_acquire_for)[.](#cnt-18.sentence-2) [19](#cnt-19) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10653) *Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")), or system_error when a non-timeout-related exception is required ([[thread.req.exception]](thread.req.exception "32.2.2 Exceptions"))[.](#cnt-19.sentence-1) [20](#cnt-20) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L10658) *Error conditions*: Any of the error conditions allowed for mutex types ([[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex "32.6.4.2 Mutex types"))[.](#cnt-20.sentence-1)