534 Stimmen

<std::unique_lock<std::mutex>> oder <std::lock_guard<std::mutex>> ?

Ich habe zwei Anwendungsfälle.

A. Ich möchte den Zugriff auf eine Warteschlange für zwei Threads synchronisieren.

B. Ich möchte den Zugriff auf eine Warteschlange für zwei Threads synchronisieren und eine Bedingungsvariable verwenden, da einer der Threads darauf wartet, dass der andere Thread Inhalte in die Warteschlange speichert.

Für Anwendungsfall A sehe ich einen Code-Beispiel, das std::lock_guard<> verwendet. Für Anwendungsfall B sehe ich einen Code-Beispiel, das std::unique_lock<> verwendet.

Was ist der Unterschied zwischen den beiden und welche sollte ich für welchen Anwendungsfall verwenden?

519voto

Stephan Dollberg Punkte 31089

Der Unterschied besteht darin, dass Sie ein std::unique_lock sperren und entsperren können. std::lock_guard wird nur einmal während der Konstruktion gesperrt und bei der Zerstörung entsperrt.

Also für Anwendungsfall B benötigen Sie definitiv einen std::unique_lock für die Bedingungsvariable. Im Fall von A hängt es davon ab, ob Sie den Wächter erneut sperren müssen.

std::unique_lock hat weitere Funktionen, die es z. B. ermöglichen, ihn ohne sofortiges Sperren des Mutex zu erstellen, aber den RAII-Wrapper zu erstellen (siehe hier).

std::lock_guard bietet auch einen bequemen RAII-Wrapper, kann jedoch nicht mehrere Mutexe sicher sperren. Es kann verwendet werden, wenn Sie einen Wrapper für einen begrenzten Bereich benötigen, z. B.: eine Member-Funktion:

class MyClass{
    std::mutex my_mutex;
    void member_foo() {
        std::lock_guard lock(this->my_mutex);            
        /*
         Codeblock, der gegenseitigen Ausschluss benötigt (z. B. öffnen der 
         gleichen Datei in mehreren Threads).
        */

        // Der Mutex wird automatisch freigegeben, wenn der Sperre aus dem Gültigkeitsbereich geht
    }           
};

Um eine Frage von chmike zu klären, sind standardmäßig std::lock_guard und std::unique_lock gleich. Also in dem obigen Fall könnten Sie std::lock_guard durch std::unique_lock ersetzen. Allerdings hat std::unique_lock möglicherweise etwas mehr Overhead.

Beachten Sie, dass heutzutage (seit C++17) man anstelle von std::lock_guard std::scoped_lock verwenden sollte.

173voto

Sebastian Redl Punkte 64533

lock_guard und unique_lock sind im Grunde dasselbe; lock_guard ist eine eingeschränkte Version mit einer begrenzten Schnittstelle.

Ein lock_guard hält immer ein Schloss von seiner Erstellung bis zu seiner Zerstörung. Ein unique_lock kann erstellt werden, ohne sofort zu sperren, kann an beliebiger Stelle in seinem Bestehen entsperren und kann den Besitz des Schlosses von einer Instanz auf eine andere übertragen.

Also verwenden Sie immer lock_guard, es sei denn, Sie benötigen die Fähigkeiten von unique_lock. Ein condition_variable benötigt einen unique_lock.

78voto

ComicSansMS Punkte 48136

Verwenden Sie lock_guard, es sei denn, Sie müssen den Mutex manuell unlock dazwischen, ohne das lock zu zerstören.

Insbesondere entsperrt condition_variable seinen Mutex beim Schlafen gehen bei Aufrufen von wait. Deshalb ist ein lock_guard hier nicht ausreichend.

Wenn Sie bereits in C++17 oder später sind, erwägen Sie die Verwendung von scoped_lock als leicht verbesserte Version von lock_guard mit den gleichen wesentlichen Fähigkeiten.

12voto

Sandeep Punkte 1187

Es gibt bestimmte gemeinsame Dinge zwischen lock_guard und unique_lock und bestimmte Unterschiede.

Aber im Zusammenhang mit der gestellten Frage erlaubt der Compiler nicht die Verwendung eines lock_guard in Kombination mit einer Bedingungsvariablen, weil wenn ein Thread auf eine Bedingungsvariable wartet, wird das Mutex automatisch entsperrt und wenn ein anderer Thread/die anderen Threads benachrichtigen und der aktuelle Thread aufgerufen wird (aus der Warteschlange kommt), wird das Schloss neu erworben.

Dieses Phänomen widerspricht dem Prinzip von lock_guard. lock_guard kann nur einmal konstruiert und nur einmal dekonstruiert werden.

Deshalb kann lock_guard nicht in Kombination mit einer Bedingungsvariable verwendet werden, aber ein unique_lock kann (weil unique_lock mehrmals gesperrt und entsperrt werden kann).

5voto

user3500315 Punkte 51

Ein fehlender Unterschied ist: std::unique_lock kann verschoben werden, aber std::lock_guard kann nicht verschoben werden.

Hinweis: Beide können nicht kopiert werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X