Класс counting_semaphore
Класс counting_semaphore представляет собой
счётный семафор - примитив синхронизации из
библиотеки thread. Семафор хранит внутренний
счётчик, который уменьшается при захвате и
увеличивается при освобождении. Если счётчик
равен нулю, поток, пытающийся захватить семафор,
блокируется до тех пор, пока другой поток не
освободит ресурс. В конструктор мы передаём
начальное значение счётчика - максимальное
количество потоков, которые могут одновременно
получить доступ к ресурсу.
Класс является шаблонным и принимает вторым
параметром максимальное значение счётчика,
которое по умолчанию равно наибольшему значению
типа ptrdiff_t. Основные методы:
acquire уменьшает счётчик и блокирует поток,
если счётчик равен нулю, try_acquire пытается
уменьшить счётчик без блокировки,
try_acquire_for и try_acquire_until
делают то же самое с ограничением по времени,
а release увеличивает счётчик и будит
ожидающие потоки.
Синтаксис
#include <semaphore>
std::counting_semaphore<MaxValue> sem(initial_value);
sem.acquire();
sem.try_acquire();
sem.try_acquire_for(duration);
sem.try_acquire_until(time_point);
sem.release(update = 1);
Пример
Давайте создадим семафор со счётчиком 2
и запустим 4 потока. Одновременно
выполняться будут только 2 потока:
#include <iostream>
#include <thread>
#include <semaphore>
#include <vector>
using namespace std;
counting_semaphore<2> sem(2);
void worker(int id)
{
sem.acquire();
cout << "Thread " << id << " acquired" << endl;
this_thread::sleep_for(chrono::milliseconds(100));
cout << "Thread " << id << " released" << endl;
sem.release();
}
int main()
{
vector<thread> threads;
for (int i = 1; i <= 4; i++) {
threads.push_back(thread(worker, i));
}
for (auto& t : threads) {
t.join();
}
return 0;
}
Результат выполнения кода:
"Thread 1 acquired"
"Thread 2 acquired"
"Thread 1 released"
"Thread 2 released"
"Thread 3 acquired"
"Thread 4 acquired"
"Thread 3 released"
"Thread 4 released"
Пример
Давайте используем метод try_acquire,
который не блокирует поток, а возвращает
true или false в зависимости от того,
удалось ли захватить семафор:
#include <iostream>
#include <semaphore>
using namespace std;
int main()
{
counting_semaphore<1> sem(1);
if (sem.try_acquire()) {
cout << "Acquired" << endl;
}
if (sem.try_acquire()) {
cout << "Acquired again" << endl;
} else {
cout << "Cannot acquire" << endl;
}
sem.release();
if (sem.try_acquire()) {
cout << "Acquired after release" << endl;
}
return 0;
}
Результат выполнения кода:
"Acquired"
"Cannot acquire"
"Acquired after release"