Files
2025-10-25 03:02:53 +03:00

252 lines
9.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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 <semaphore> synopsis [[semaphore.syn]](semaphore.syn)
[🔗](#header:%3csemaphore%3e)
namespace std {// [[thread.sema.cnt]](#cnt "32.8.3Class template counting_­semaphore"), class template counting_semaphoretemplate<ptrdiff_t least_max_value = *implementation-defined*>class counting_semaphore; using [binary_semaphore](#lib:binary_semaphore "32.8.2Header <semaphore> synopsis[semaphore.syn]") = counting_semaphore<1>;}
### [32.8.3](#cnt) Class template counting_semaphore [[thread.sema.cnt]](thread.sema.cnt)
namespace std {template<ptrdiff_t least_max_value = *implementation-defined*>class 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; template<class Rep, class Period>bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_acquire_until(const chrono::time_point<Clock, Duration>& 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.2Exceptions"))[.](#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.2Mutex 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.5Atomic 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.2Exceptions"))[.](#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.2Mutex types"))[.](#cnt-17.sentence-1)
[🔗](#lib:try_acquire_for,counting_semaphore)
`template<class Rep, class Period>
bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
template<class Clock, class Duration>
bool try_acquire_until(const chrono::time_point<Clock, Duration>& 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.4Timing 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.4Timing specifications")), or system_error when a non-timeout-related exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#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.2Mutex types"))[.](#cnt-20.sentence-1)