std::shared_mutex
| Definiert in Header <shared_mutex> |
||
| class shared_mutex; |
(seit C++17) | |
Die Klasse shared_mutex ist ein Synchronisationsprimitiv, das verwendet werden kann, um den Zugriff auf geteilte Daten zu schützen, damit sie nicht gleichzeitig von mehreren Threads zugegriffen werden können. Im Gegensatz zu anderen Mutex-Typen, die exklusiven Zugriff ermöglichen, hat ein shared_mutex zwei Zugriffsebenen:
- shared (geteilt) - mehrere Threads können den Besitz desselben Mutex teilen.
- exclusive (exklusiv) - nur ein Thread kann den Mutex besitzen.
Wenn ein Thread den exklusiven Lock erworben hat (über lock, try_lock), können keine anderen Threads den Lock erwerben (einschließlich des shared).
Wenn ein Thread den shared Lock erworben hat (über lock_shared, try_lock_shared), kann kein anderer Thread den exklusiven Lock erwerben, aber er kann den shared Lock erwerben.
Nur wenn der exklusive Lock von keinem Thread erworben wurde, kann der shared Lock von mehreren Threads erworben werden.
Innerhalb eines Threads kann zu jeder Zeit nur ein Lock (shared oder exclusive) erworben werden.
Shared Mutexes sind besonders nützlich, wenn geteilte Daten sicher von beliebig vielen Threads gleichzeitig gelesen werden können, aber ein Thread dieselben Daten nur schreiben darf, wenn kein anderer Thread gleichzeitig liest oder schreibt.
Die Klasse shared_mutex erfüllt alle Anforderungen von SharedMutex und StandardLayoutType.
Inhalt |
[bearbeiten] Member types
| Mitgliedertyp | Definition |
native_handle_type (optional*) |
implementierungsabhängig |
[bearbeiten] Member functions
| konstruiert den Mutex (public member function) | |
| zerstört den Mutex (public member function) | |
| operator= [gelöscht] |
nicht kopierbar (public member function) |
Exklusives Sperren | |
| sperrt den Mutex, blockiert, wenn der Mutex nicht verfügbar ist (public member function) | |
| versucht, den Mutex zu sperren, kehrt zurück, wenn der Mutex nicht verfügbar ist (public member function) | |
| entsperrt den Mutex (public member function) | |
| | |
| sperrt den Mutex für gemeinsamen Besitz, blockiert, wenn der Mutex nicht verfügbar ist (public member function) | |
| versucht, den Mutex für gemeinsamen Besitz zu sperren, kehrt zurück, wenn der Mutex nicht verfügbar ist (public member function) | |
| entsperrt den Mutex (gemeinsamer Besitz) (public member function) | |
Native handle | |
| gibt das implementierungsabhängige native Handle-Objekt zurück (public member function) | |
[bearbeiten] Beispiel
Die untenstehende Ausgabe wurde auf einem Single-Core-Rechner erzeugt. Wenn thread1 startet, tritt es zum ersten Mal in die Schleife ein und ruft increment() gefolgt von get() auf. Bevor es jedoch den zurückgegebenen Wert nach std::cout ausgeben kann, versetzt der Scheduler thread1 in den Schlaf und weckt thread2 auf, das offensichtlich genügend Zeit hat, alle drei Schleifendurchläufe auf einmal auszuführen. Zurück zu thread1, immer noch im ersten Schleifendurchlauf, gibt es schließlich seine lokale Kopie des Zählerwerts, nämlich 1, nach std::cout aus und führt dann die verbleibenden zwei Schleifendurchläufe aus. Auf einem Multi-Core-Rechner wird keiner der Threads in den Schlaf versetzt, und die Ausgabe ist eher aufsteigend.
#include <iostream> #include <mutex> #include <shared_mutex> #include <syncstream> #include <thread> class ThreadSafeCounter { public: ThreadSafeCounter() = default; // Multiple threads/readers can read the counter's value at the same time. unsigned int get() const { std::shared_lock lock(mutex_); return value_; } // Only one thread/writer can increment/write the counter's value. void increment() { std::unique_lock lock(mutex_); ++value_; } // Only one thread/writer can reset/write the counter's value. void reset() { std::unique_lock lock(mutex_); value_ = 0; } private: mutable std::shared_mutex mutex_; unsigned int value_{}; }; int main() { ThreadSafeCounter counter; auto increment_and_print = [&counter]() { for (int i{}; i != 3; ++i) { counter.increment(); std::osyncstream(std::cout) << std::this_thread::get_id() << ' ' << counter.get() << '\n'; } }; std::thread thread1(increment_and_print); std::thread thread2(increment_and_print); thread1.join(); thread2.join(); }
Mögliche Ausgabe
123084176803584 2 123084176803584 3 123084176803584 4 123084185655040 1 123084185655040 5 123084185655040 6
[bearbeiten] Siehe auch
| (C++14) |
bietet gemeinsame Gegenseitiger-Ausschluss-Funktionen und implementiert ein Sperren mit Timeout (Klasse) |
| (C++14) |
implementiert verschiebbaren Shared-Mutex-Besitz-Wrapper (Klassenvorlage) |
| (C++11) |
implementiert verschiebbaren Mutex-Besitz-Wrapper (Klassenvorlage) |