Scroll to navigation

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 <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( 128 /*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) {
n *= x_scale;
while (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 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████

2022.07.31 http://cppreference.com