std::counting_semaphore::acquire - cppreference.com (original) (raw)

| void acquire(); | | (since C++20) | | --------------- | | ------------- |

Atomically decrements the internal counter by 1 if it is greater than ​0​; otherwise blocks until it is greater than ​0​ and can successfully decrement the internal counter.

[edit] Preconditions

(none)

[edit] Parameters

(none)

[edit] Exceptions

May throw std::system_error.

[edit] Example

The example visualizes a concurrent work of several randomized threads when no more than N (N is the semaphore desired value) of the thread-functions are active, while the other might wait on the semaphore.

#include #include #include #include #include #include #include #include #include #include #include   using namespace std::literals;   constexpr std::size_t max_threads{10U}; // change and see the effect constexpr std::ptrdiff_t max_sema_threads{3}; // {1} for binary semaphore std::counting_semaphore semaphore{max_sema_threads}; constexpr auto time_tick{10ms};   unsigned rnd() { static std::uniform_int_distribution distribution{2U, 9U}; // [delays] static std::random_device engine; static std::mt19937 noise{engine()}; return distribution(noise); }   class alignas(std::hardware_destructive_interference_size) Guide { inline static std::mutex cout_mutex; inline static std::chrono::time_point<std::chrono::high_resolution_clock> started_at; unsigned delay{rnd()}, occupy{rnd()}, wait_on_sema{};   public: static void start_time() { started_at = std::chrono::high_resolution_clock::now(); }   void initial_delay() { std::this_thread::sleep_for(delay * time_tick); }   void occupy_sema() { wait_on_sema = static_cast(std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - started_at - delay * time_tick).count() / time_tick.count()); std::this_thread::sleep_for(occupy * time_tick); }   void visualize(unsigned id, unsigned x_scale = 2) const { auto cout_n = [=](auto str, unsigned n) { for (n *= x_scale; n-- > 0; std::cout << str) ; }; std::lock_guard lk{cout_mutex}; std::cout << '#' << std::setw(2) << id << ' '; cout_n("░", delay); cout_n("▒", wait_on_sema); cout_n("█", occupy); std::cout << '\n'; }   static void show_info() { std::cout << "\nThreads: " << max_threads << ", Throughput: " << max_sema_threads << " │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██ \n" << std::endl; } };   std::array<Guide, max_threads> guides;   void workerThread(unsigned id) { guides[id].initial_delay(); // emulate some work before sema acquisition semaphore.acquire(); // wait until a free sema slot is available guides[id].occupy_sema(); // emulate some work while sema is acquired semaphore.release(); guides[id].visualize(id); }   int main() { std::vector<std::jthread> threads; threads.reserve(max_threads);   Guide::show_info(); Guide::start_time();   for (auto id{0U}; id != max_threads; ++id) threads.push_back(std::jthread(workerThread, id)); }

Possible output:

Default case: max_threads{10U}, max_sema_threads{3}   Threads: 10, Throughput: 3 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██  

1 ░░░░██████

2 ░░░░████████

5 ░░░░░░██████████

8 ░░░░░░░░░░░░████████████

9 ░░░░░░░░░░░░██████████████

7 ░░░░░░░░░░░░▒▒▒▒████████████████

4 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒████████

6 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒██████████████████

3 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████

0 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████

  ────────────────────────────────────────────────────────────────────────────────────────────────────────────── "Enough for everyone" case (no wait states!): max_threads{10U}, max_sema_threads{10}   Threads: 10, Throughput: 10 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██  

4 ░░░░██████

5 ░░░░░░████

3 ░░░░██████████

1 ░░░░██████████

8 ░░░░░░░░████████████

6 ░░░░░░░░░░░░░░░░██████

7 ░░░░░░░░░░░░░░░░██████

9 ░░░░░░░░░░░░░░░░██████████

0 ░░░░░░░░░░░░██████████████████

2 ░░░░░░░░░░░░░░░░░░████████████

  ────────────────────────────────────────────────────────────────────────────────────────────────────────────── Binary semaphore case: max_threads{10U}, max_sema_threads{1}   Threads: 10, Throughput: 1 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██  

6 ░░░░████

5 ░░░░▒▒▒▒████

4 ░░░░░░░░░░▒▒██████████

7 ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒████████████████

2 ░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████

3 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████████

0 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████

1 ░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████

8 ░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████

9 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████

[edit] See also

| | increments the internal counter and unblocks acquirers (public member function) [edit] | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | | tries to decrement the internal counter without blocking (public member function) [edit] | | | tries to decrement the internal counter, blocking for up to a duration time (public member function) [edit] | | | tries to decrement the internal counter, blocking until a point in time (public member function) [edit] |