C++-Standardbibliothek<mutex>
In der Multithread-Programmierung ist die Gewährleistung von Datenkonsistenz und Thread-Sicherheit entscheidend.
Die C++-Standardbibliothek bietet eine reichhaltige Sammlung von Synchronisierungsprimitiven, die verwendet werden, um den Zugriff auf gemeinsam genutzte Ressourcen zu steuern.
In der C++-Standardbibliothek,<mutex>Die Header-Datei bietet eine Reihe von Werkzeugen zur Implementierung von Synchronisation und gegenseitigem Ausschluss zwischen Threads in Multithread-Programmen.
<mutex>Die Header-Datei wurde in C++11 eingeführt und enthält Klassen und Funktionen für Mutex-Sperren. Eine Mutex-Sperre ist ein Synchronisierungsmechanismus, der verwendet wird, um zu verhindern, dass mehrere Threads gleichzeitig auf gemeinsam genutzte Ressourcen zugreifen.
Ein Mutex ist ein Synchronisierungsprimitiv, das verwendet wird, um den Zugriff auf gemeinsam genutzte Ressourcen zu steuern. Wenn ein Thread auf eine gemeinsam genutzte Ressource zugreifen muss, versucht er, den Mutex zu sperren. Wenn der Mutex bereits von einem anderen Thread gesperrt wurde, wird der anfordernde Thread blockiert, bis der Mutex freigegeben wird.
Grundlegende Syntax
In C++,<mutex>Die Header-Datei bietet die folgenden Hauptklassen:
std::mutex: Einfacher Mutex.std::recursive_mutex: Rekursive Mutex-Sperre, die es demselben Thread ermöglicht, mehrfach zu sperren.std::timed_mutex: Mutex mit Timeout-Funktionalität.std::recursive_timed_mutex: Rekursiver Mutex mit Timeout-Funktionalität.
Beispiel
1. Verwendungstd::mutex
Das Folgende ist ein einfaches Beispiel, das zeigt, wie man es in C++ verwendetstd::mutexum den Zugriff auf gemeinsam genutzte Ressourcen zu synchronisieren.
Beispiel
#include <thread>
#include <mutex>
std::mutex mtx; // Globale Mutex-Sperre
int shared_resource = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
mtx.lock(); // Mutex sperren
++shared_resource;
mtx.unlock(); // Mutex entsperren
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Endgültiger Wert von shared_resource: " << shared_resource << std::endl;
return 0;
}
Ausgabeergebnis:
Final value of shared_resource: 20000
2. Verwendungstd::recursive_mutex
Ein rekursiver Mutex-Lock ermöglicht es demselben Thread, denselben Mutex mehrmals zu sperren. Das Folgende ist ein Beispiel unter Verwendung vonstd::recursive_mutexBeispiel.
Beispiel
#include <thread>
#include <mutex>
std::recursive_mutex rmtx; // Rekursives Mutex-Objekt erstellen
int shared_resource = 0; // Gemeinsam genutzte Ressource
// Rekursive Funktion
void recursive_increment(int count) {
if (count <= 0) return;
std::lock_guard<std::recursive_mutex> lock(rmtx); // Sperren, um Thread-Sicherheit zu gewährleisten
++shared_resource;
std::cout << "shared_resource inkrementiert auf " << shared_resource << " (count = " << count << ")" << std::endl;
// Rekursiver Aufruf
recursive_increment(count - 1);
}
int main() {
std::thread t1(recursive_increment, 3); // Thread t1 führt recursive_increment(3) aus
std::thread t2(recursive_increment, 3); // Thread t2 führt recursive_increment(3) aus
t1.join(); // Warten, bis Thread t1 beendet ist
t2.join(); // Warten, bis Thread t2 beendet ist
std::cout << "Endgültiger Wert von shared_resource: " << shared_resource << std::endl;
return 0;
}
Ausgabeergebnis:
Incremented shared_resource to 1 (count = 3) Incremented shared_resource to 2 (count = 2) Incremented shared_resource to 3 (count = 1) Incremented shared_resource to 4 (count = 0) Incremented shared_resource to 5 (count = 3) Incremented shared_resource to 6 (count = 2) Incremented shared_resource to 7 (count = 1) Incremented shared_resource to 8 (count = 0) Final value of shared_resource: 8
Codeanalyse:
Erstelle
std::recursive_mutexObjekt:std::recursive_mutex rmtx;Ist ein rekursiver Mutex, der es demselben Thread ermöglicht, die Sperre mehrfach zu erwerben.Gemeinsam genutzte Ressource:
int shared_resource = 0;ist eine Ressource, auf die mehrere Threads gleichzeitig zugreifen.Rekursive Funktion
recursive_increment:- Nutzung
std::lock_guard<std::recursive_mutex>PairrmtxSperren. Da ein rekursiver Mutex verwendet wird, kann derselbe Thread die Sperre mehrmals erwerben. - Durch
++shared_resourceErhöht den Wert der gemeinsam genutzten Ressource. - Die Funktion ruft sich selbst rekursiv auf und veranschaulicht, wie eine rekursive Funktion sicher funktioniert, wenn die Sperre mehrmals erworben wird.
- Nutzung
Erstellen und Ausführen von Threads:
std::thread t1(recursive_increment, 3);undstd::thread t2(recursive_increment, 3);Zwei Threads werden separat erstellt, und beide werden ausgeführtrecursive_increment(3)。t1.join()undt2.join()Wartet darauf, dass zwei Threads ihre Ausführung abschließen.
Hinweise
- Stellen Sie sicher, dass nach jedem Erwerb einer Mutex-Sperre eine Entsperroperation ausgeführt wird, um Deadlocks zu vermeiden.
- Nutzung
std::lock_guardoderstd::unique_lockKann das Sperren und Entsperren von Mutex-Sperren automatisch verwalten, wodurch die Wahrscheinlichkeit von Fehlern verringert wird. - Vermeiden Sie den Aufruf von Funktionen, die Ausnahmen auslösen können, während eine Mutex-Sperre gehalten wird, da dies zu einem Deadlock führen kann.
<mutex>Ist eine sehr wichtige Header-Datei in der C++-Standardbibliothek und bietet grundlegende Synchronisationsmechanismen für die Multithread-Programmierung. Durch die Verwendung von Mutex-Sperren können wir sicherstellen, dass der Zugriff auf gemeinsam genutzte Ressourcen sicher ist, wodurch Datenrennen und Inkonsistenzprobleme vermieden werden.
Weitere Informationen
1. std::mutex
Bietet einen grundlegenden Mutex, um sicherzustellen, dass nur ein Thread gleichzeitig auf gemeinsam genutzte Ressourcen zugreifen kann.
Beispiel
std::mutex mtx;
void thread_function() {
std::lock_guard<std::mutex> lock(mtx);
// Zugriff auf gemeinsame Ressource
}
2. std::recursive_mutex
Ermöglicht demselben Thread, die Sperre mehrmals zu erwerben, ohne einen Deadlock zu verursachen, was besonders nützlich für rekursive Funktionen ist.
Beispiel
std::recursive_mutex rmtx;
void recursive_function(int count) {
if (count <= 0) return;
std::lock_guard<std::recursive_mutex> lock(rmtx);
// Rekursiver Aufruf
recursive_function(count - 1);
}
3. std::timed_mutex
Stellt einen zeitgesteuerten Mutex bereit, der beim Versuch, die Sperre zu erwerben, eine Zeitüberschreitung festlegen kann.
Beispiel
#include <chrono>
std::timed_mutex tm;
void try_lock_for_example() {
if (tm.try_lock_for(std::chrono::seconds(1))) {
// Sperre erfolgreich erworben
tm.unlock();
} else {
// Sperre konnte nicht erworben werden
}
}
4. std::recursive_timed_mutex
Von std::timed_mutex geerbt, wodurch derselbe Thread die Sperre mehrmals erwerben kann und gleichzeitig zeitgesteuerte Funktionalität unterstützt wird.
Beispiel
#include <chrono>
std::recursive_timed_mutex rtm;
void recursive_timed_function(int count) {
if (count <= 0) return;
if (rtm.try_lock_for(std::chrono::seconds(1))) {
// Sperre erfolgreich erworben
recursive_timed_function(count - 1);
rtm.unlock();
} else {
// Sperre konnte nicht erworben werden
}
}
5. std::lock_guard
Ein Wrapper, der std::mutex-Sperren automatisch verwaltet und dabei den RAII-Stil verwendet, um sicherzustellen, dass die Sperre automatisch freigegeben wird, wenn der Gültigkeitsbereich endet.
Beispiel
std::mutex mtx;
void function() {
std::lock_guard<std::mutex> lock(mtx);
// Zugriff auf gemeinsame Ressource
}
6. std::unique_lock
Bietet eine flexiblere Sperrenverwaltung als std::lock_guard, ermöglicht manuelles Freigeben und erneutes Erwerben von Sperren und unterstützt außerdem zeitgesteuertes Sperren.
Beispiel
#include <chrono>
std::mutex mtx;
void function() {
std::unique_lock<std::mutex> lock(mtx);
// Zugriff auf gemeinsame Ressource
// Sperre kann manuell freigegeben werden
lock.unlock();
// Sperre kann erneut erworben werden
lock.lock();
// Zeitgesteuertes Sperren möglich
if (lock.try_lock_for(std::chrono::seconds(1))) {
// Sperre erfolgreich erworben
}
}
7. std::adopt_lock_t
Ein Flag-Typ, der verwendet wird, um anzugeben, dass std::unique_lock eine vorhandene Sperre übernimmt.
Beispiel
std::unique_lock<std::mutex> lock(mtx, std::adopt_lock);
8. std::defer_lock_t
Funktion: Ein Flag-Typ, der für verzögertes Sperren verwendet wird; während der Initialisierung wird keine Sperre erworben.
Beispiel
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// lock.lock() kann zu einem späteren Zeitpunkt aufgerufen werden
9. std::try_to_lock_t
Flag-Typ, der verwendet wird, um ohne Blockieren eine Sperre zu versuchen.
Beispiel
std::unique_lock<std::mutex> lock1(mtx1, std::try_to_lock);
std::unique_lock<std::mutex> lock2(mtx2, std::try_to_lock);
if (lock1 && lock2) {
// Beide Sperren erfolgreich erworben
}