std::counting_semaphore, std::binary_semaphore
| Definiert in Header <semaphore> |
||
| template< std::ptrdiff_t LeastMaxValue = /* implementierungsdefiniert */ > class counting_semaphore; |
(1) | (seit C++20) |
| using binary_semaphore = std::counting_semaphore<1>; |
(2) | (seit C++20) |
counting_semaphore ist ein leichtgewichtiges Synchronisationsprimitiv, das den Zugriff auf eine gemeinsam genutzte Ressource steuern kann. Im Gegensatz zu einem std::mutex erlaubt ein counting_semaphore mehr als einen gleichzeitigen Zugriff auf dieselbe Ressource, für mindestens LeastMaxValue gleichzeitige Zugreifer. Das Programm ist schlecht formuliert, wenn LeastMaxValue negativ ist.binary_semaphore ist ein Alias für eine Spezialisierung von std::counting_semaphore mit LeastMaxValue gleich 1. Implementierungen können binary_semaphore effizienter als die Standardimplementierung von std::counting_semaphore implementieren.Ein counting_semaphore enthält einen internen Zähler, der durch den Konstruktor initialisiert wird. Dieser Zähler wird durch Aufrufe von acquire() und verwandten Methoden dekrementiert und durch Aufrufe von release() inkrementiert. Wenn der Zähler Null ist, blockiert acquire(), bis der Zähler inkrementiert wird, aber try_acquire() blockiert nicht; try_acquire_for() und try_acquire_until() blockieren, bis der Zähler inkrementiert wird oder ein Timeout erreicht ist.
Ähnlich wie bei std::condition_variable::wait() kann try_acquire() von counting_semaphore aus unerklärlichen Gründen fehlschlagen.
Spezialisierungen von std::counting_semaphore sind nicht DefaultConstructible, CopyConstructible, MoveConstructible, CopyAssignable oder MoveAssignable.
Inhalt |
[bearbeiten] Datenmember
| Member-Name | Definition |
counter (private) |
Der interne Zähler vom Typ std::ptrdiff_t. ((exposition-only member object*) |
[bearbeiten] Memberfunktionen
konstruiert einen counting_semaphore(public member function) | |
zerstört den counting_semaphore(public member function) | |
| operator= [gelöscht] |
counting_semaphore ist nicht zuweisbar(public member function) |
Operationen | |
| inkrementiert den internen Zähler und gibt blockierende Erwerber frei (public member function) | |
| dekrementiert den internen Zähler oder blockiert, bis dies möglich ist (public member function) | |
| versucht, den internen Zähler zu dekrementieren, ohne zu blockieren (public member function) | |
| versucht, den internen Zähler zu dekrementieren, blockiert für eine Dauer von bis zu time (public member function) | |
| versucht, den internen Zähler zu dekrementieren, blockiert bis zu einem Zeitpunkt (public member function) | |
Konstanten | |
| [static] |
gibt den maximal möglichen Wert des internen Zählers zurück (public static member function) |
[bearbeiten] Hinweise
Wie der Name schon sagt, ist LeastMaxValue der *minimale* Maximalwert, nicht der *tatsächliche* Maximalwert. Daher kann max() eine Zahl größer als LeastMaxValue liefern.
Im Gegensatz zu std::mutex ist ein counting_semaphore nicht an Ausführungs-Threads gebunden - der Erwerb eines Semaphors kann auf einem anderen Thread als die Freigabe des Semaphors erfolgen, zum Beispiel. Alle Operationen auf counting_semaphore können gleichzeitig und ohne Bezug zu bestimmten Ausführungs-Threads durchgeführt werden, mit Ausnahme des Destruktors, der nicht gleichzeitig durchgeführt werden kann, aber auf einem anderen Thread ausgeführt werden kann.
Semaphoren werden auch oft für die Semantik des Signalens/Benachrichtigens anstelle von gegenseitigem Ausschluss verwendet, indem der Semaphor mit 0 initialisiert wird und somit die Empfänger, die versuchen, zu acquire(), blockiert, bis der Benachrichtiger durch Aufrufen von release(n) "signalisiert". In dieser Hinsicht können Semaphoren als Alternativen zu std::condition_variables betrachtet werden, oft mit besserer Leistung.
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_semaphore |
201907L |
(C++20) | std::counting_semaphore, std::binary_semaphore |
[bearbeiten] Beispiel
#include <chrono> #include <iostream> #include <semaphore> #include <thread> // global binary semaphore instances // object counts are set to zero // objects are in non-signaled state std::binary_semaphore smphSignalMainToThread{0}, smphSignalThreadToMain{0}; void ThreadProc() { // wait for a signal from the main proc // by attempting to decrement the semaphore smphSignalMainToThread.acquire(); // this call blocks until the semaphore's count // is increased from the main proc std::cout << "[thread] Got the signal\n"; // response message // wait for 3 seconds to imitate some work // being done by the thread using namespace std::literals; std::this_thread::sleep_for(3s); std::cout << "[thread] Send the signal\n"; // message // signal the main proc back smphSignalThreadToMain.release(); } int main() { // create some worker thread std::thread thrWorker(ThreadProc); std::cout << "[main] Send the signal\n"; // message // signal the worker thread to start working // by increasing the semaphore's count smphSignalMainToThread.release(); // wait until the worker thread is done doing the work // by attempting to decrement the semaphore's count smphSignalThreadToMain.acquire(); std::cout << "[main] Got the signal\n"; // response message thrWorker.join(); }
Ausgabe
[main] Send the signal [thread] Got the signal [thread] Send the signal [main] Got the signal