In modernem C++ (seit C++11) gibt es eine umfangreiche Werkzeugkiste für die Arbeit mit Multithreading: std::thread, Mutexes und verschiedene Wrapper-Objekte zur Steuerung des Zugriffs auf Ressourcen. Sicheres Interagieren zwischen Threads erfordert das Verständnis der folgenden Komponenten:
Um Rennbedingungen zu vermeiden, verwenden Sie immer RAII-Wrappers wo möglich. Beachten Sie, dass der Versuch, den gleichen Mutex erneut zu sperren, zu einem Deadlock führen kann (es sei denn, es ist ein rekursiver Mutex).
Ein Beispiel für sicheres Arbeiten:
#include <iostream> #include <mutex> #include <thread> std::mutex mtx; void printThreadSafe(int id) { std::lock_guard<std::mutex> lock(mtx); std::cout << "Thread " << id << std::endl; } int main() { std::thread t1(printThreadSafe, 1); std::thread t2(printThreadSafe, 2); t1.join(); t2.join(); }
Kann std::lock_guardstd::mutex zur Implementierung bedingter Synchronisation mit std::condition_variable verwendet werden?
Antwort: Nein! Für die Arbeit mit std::condition_variable ist unbedingt std::unique_lockstd::mutex erforderlich, da lock_guard keine Methoden zur Steuerung der Sperre bereitstellt (z. B. vorübergehendes Freigeben — unlock — und dann erneut erlangen), die beim Warten auf eine Benachrichtigung notwendig sind.
Beispiel:
std::mutex mtx; std::condition_variable cv; bool ready = false; void waitForEvent() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{return ready;}); // Weitere Verarbeitung }
Geschichte
Im Projekt wurde manuell mit mtx.lock()/mtx.unlock() gearbeitet. Bei einer Ausnahme zwischen lock/unlock blieb der Mutex blockiert — viele Threads „hängten“. Nachdem auf RAII (
std::lock_guard) umgestiegen wurde, verschwand das Problem.
Geschichte
Beim Benachrichtigen über std::condition_variable wurde std::lock_guard anstelle von std::unique_lock verwendet. Infolgedessen ließ sich das Programm in neuen Compilern nicht kompilieren, und beim alten trat zur Laufzeit eine Assertionsfehler aufgrund einer inkonsistenten API auf.
Geschichte
Im Code wurde unlock() bei std::lock_guard aufgerufen, um den Zugriff auf den Mutex „manuell“ zu steuern. Dies führte zu undefiniertem Verhalten in verschiedenen Compilern, manchmal zum Absturz der Anwendung. Es wurde klar, dass lock_guard keine manuelle Freigabe unterstützt, ein Umstieg auf unique_lock erforderlich war.