table of contents
std::counting_semaphore::acquire(3) | C++ Standard Libary | std::counting_semaphore::acquire(3) |
NAME¶
std::counting_semaphore::acquire - std::counting_semaphore::acquire
Synopsis¶
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.
Preconditions¶
(none)
Parameters¶
(none)
Exceptions¶
May throw std::system_error.
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.
// Run this code
#include <array>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <new>
#include <random>
#include <semaphore>
#include <thread>
#include <vector>
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<unsigned> 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<unsigned>(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
░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████
See also¶
release increments the internal counter and unblocks acquirers
(public member function)
try_acquire tries to decrement the internal counter without blocking
(public member function)
tries to decrement the internal counter, blocking for up to a
try_acquire_for duration time
(public member function)
tries to decrement the internal counter, blocking until a point in
try_acquire_until time
(public member function)
2024.06.10 | http://cppreference.com |