Der Unterschied besteht darin, dass Sie a sperren und entsperren können std::unique_lock
. std::lock_guard
wird beim Bau nur einmal gesperrt und bei Zerstörung entsperrt.
Für Anwendungsfall B benötigen Sie also definitiv eine std::unique_lock
für die Bedingungsvariable. In Fall A hängt es davon ab, ob Sie den Schutz wieder verriegeln müssen.
std::unique_lock
hat andere Funktionen, die es ermöglichen, zB: ohne sofortiges Sperren des Mutex zu konstruieren, aber den RAII-Wrapper zu erstellen (siehe hier ).
std::lock_guard
bietet auch einen praktischen RAII-Wrapper, kann jedoch mehrere Mutexe nicht sicher sperren. Es kann verwendet werden, wenn Sie einen Wrapper für einen begrenzten Bereich benötigen, z. B.: Eine Mitgliedsfunktion:
class MyClass{
std::mutex my_mutex;
void member_foo() {
std::lock_guard<mutex_type> lock(this->my_mutex);
/*
block of code which needs mutual exclusion (e.g. open the same
file in multiple threads).
*/
//mutex is automatically released when lock goes out of scope
};
Um eine Frage von chmike zu klären, sind standardmäßig std::lock_guard
und std::unique_lock
gleich. So im obigen Fall, könnten Sie ersetzen std::lock_guard
mit std::unique_lock
. Allerdings std::unique_lock
haben könnte mehr Aufwand ein bisschen.
Beachten Sie, dass in diesen Tagen sollte man verwenden std::scoped_lock
statt std::lock_guard
.
std::lock_guard
es für Ihren Fall A ausreicht, sollten Sie es verwenden. Dies vermeidet nicht nur unnötigen Overhead, sondern zeigt dem Leser auch die Absicht, diesen Schutz niemals freizuschalten.unique_lock
wahrscheinlich durch die Kosten für das tatsächliche Sperren und Entsperren des Mutex in den Schatten gestellt wird (wenn der Compiler diesen Overhead nicht optimiert hätte, was möglich sein könnte).So for usecase B you definitely need a std::unique_lock for the condition variable
- ja, aber nur in dem Thread, dercv.wait()
s ist, weil diese Methode den Mutex atomar freigibt. In dem anderen Thread, in dem Sie die gemeinsam genutzten Variablen aktualisieren und dann aufrufencv.notify_one()
, reicht ein einfacheslock_guard
aus, um den Mutex im Gültigkeitsbereich zu sperren ... es sei denn, Sie tun etwas Aufwändigeres, das ich mir nicht vorstellen kann! zB en.cppreference.com/w/cpp/thread/condition_variable - funktioniert für mich :)lock_guard
undunique_lock
sind so ziemlich das Gleiche;lock_guard
ist eine eingeschränkte Version mit einer eingeschränkten Schnittstelle.A
lock_guard
hält immer ein Schloss von seiner Konstruktion bis zu seiner Zerstörung. Aunique_lock
kann ohne sofortige Sperrung erstellt werden, kann zu jedem Zeitpunkt seiner Existenz entsperrt werden und kann das Eigentum an der Sperre von einer Instanz auf eine andere übertragen.Sie verwenden also immer
lock_guard
, es sei denn, Sie benötigen die Funktionen vonunique_lock
. Acondition_variable
braucht aunique_lock
.quelle
A condition_variable needs a unique_lock.
- ja aber nur auf derwait()
ing Seite, wie in meinem Kommentar zu inf ausgeführt.Verwenden
lock_guard
Sie diese Option, es sei denn, Sie müssen in der Lage sein,unlock
den Mutex dazwischen manuell zu erstellen, ohne den zu zerstörenlock
.condition_variable
Entsperrt insbesondere seinen Mutex, wenn er bei Anrufen in den Ruhezustand gehtwait
. Deshalblock_guard
reicht a hier nicht aus.quelle
lock_guard
und ihn zu entsperren, wodurch die Klasseninvariante der Wache vorübergehend unterbrochen wird. Auch wenn dies für den Benutzer unsichtbar ist, würde ich dies als legitimen Grund dafür betrachten, die Verwendunglock_guard
in diesem Fall nicht zuzulassen .lock_guard
dass das Abrufen des zugrunde liegenden Mutex überhaupt nicht möglich ist. Dies ist eine bewusste Einschränkung, um eine einfachere Argumentation für Code zu ermöglichen, der verwendet wird,lock_guard
im Gegensatz zu Code, der a verwendetunique_lock
. Die einzige Möglichkeit, das zu erreichen, was Sie verlangen, besteht darin, die Kapselung derlock_guard
Klasse absichtlich zu unterbrechen und ihre Implementierung einer anderen Klasse (in diesem Fall dercondition_variable
) auszusetzen . Dies ist ein schwieriger Preis für den fragwürdigen Vorteil des Benutzers einer Bedingungsvariablen, der sich nicht an den Unterschied zwischen den beiden Sperrtypen erinnern muss.condition_variable_any.wait
mit einem funktionieren würdelock_guard
? Die Norm verlangt, dass der bereitgestellteBasicLockable
Sperrtyp die Anforderung erfüllt (§30.5.2), waslock_guard
nicht der Fall ist. Nur der zugrunde liegende Mutex funktioniert, aber aus Gründen, auf die ich bereits hingewiesen habe, bietet die Schnittstelle vonlock_guard
keinen Zugriff auf den Mutex.Es gibt bestimmte Gemeinsamkeiten zwischen
lock_guard
undunique_lock
und bestimmte Unterschiede.Im Kontext der gestellten Frage erlaubt der Compiler jedoch nicht die Verwendung einer
lock_guard
in Kombination mit einer Bedingungsvariablen, da der Mutex automatisch entsperrt wird, wenn ein Thread auf eine Bedingungsvariable wartet, und wenn andere Threads / Threads und der aktuelle Thread benachrichtigt werden wird aufgerufen (kommt aus der Wartezeit), wird die Sperre wiedererlangt.Dieses Phänomen widerspricht dem Prinzip von
lock_guard
.lock_guard
kann nur einmal konstruiert und nur einmal zerstört werden.Daher
lock_guard
kann nicht in Kombination mit einer Bedingungsvariablen verwendet werden, aber aunique_lock
kann (weilunique_lock
mehrmals gesperrt und entsperrt werden kann).quelle
he compiler does not allow using a lock_guard in combination with a condition variable
Das ist falsch. Es sicherlich nicht erlauben und arbeitet perfekt mit einemlock_guard
auf dernotify()
ing Seite. Nur diewait()
int-Seite erfordert einunique_lock
, dawait()
die Sperre freigegeben werden muss, während auf den Zustand geprüft wird.Sie sind nicht wirklich die gleichen Mutexe,
lock_guard<muType>
haben fast die gleichen wiestd::mutex
, mit dem Unterschied, dass ihre Lebensdauer am Ende des Bereichs endet (D-tor genannt), also eine klare Definition dieser beiden Mutexe:Und
Hier ist ein Beispiel für die Implementierung:
In diesem Beispiel habe ich das
unique_lock<muType>
mit verwendetcondition variable
quelle
Wie bereits von anderen erwähnt, verfolgt std :: unique_lock den Sperrstatus des Mutex, sodass Sie das Sperren bis nach dem Aufbau des Schlosses verschieben und vor dem Zerstören des Schlosses entsperren können. std :: lock_guard erlaubt dies nicht.
Es scheint keinen Grund zu geben, warum die Wartefunktionen std :: condition_variable nicht sowohl einen lock_guard als auch einen unique_lock verwenden sollten, da der Mutex bei jedem Ende einer Wartezeit (aus welchem Grund auch immer) automatisch neu erfasst wird, sodass keine semantische Verletzung auftritt. Um jedoch einen std :: lock_guard mit einer Bedingungsvariablen zu verwenden, müssen Sie gemäß dem Standard eine std :: condition_variable_any anstelle von std :: condition_variable verwenden.
Bearbeiten : gelöscht "Mit der pthreads-Schnittstelle sollten std :: condition_variable und std :: condition_variable_any identisch sein". Zum Blick auf die Implementierung von gcc:
quelle