La différence est que vous pouvez verrouiller et déverrouiller a std::unique_lock
. std::lock_guard
sera verrouillé une seule fois lors de la construction et déverrouillé lors de la destruction.
Donc, pour le cas d'utilisation B, vous avez certainement besoin d'un std::unique_lock
pour la variable de condition. Dans le cas A, cela dépend si vous devez reverrouiller la garde.
std::unique_lock
a d'autres fonctionnalités qui lui permettent par exemple: d'être construit sans verrouiller le mutex immédiatement mais de construire le wrapper RAII (voir ici ).
std::lock_guard
fournit également un wrapper RAII pratique, mais ne peut pas verrouiller plusieurs mutex en toute sécurité. Il peut être utilisé lorsque vous avez besoin d'un wrapper pour une portée limitée, par exemple: une fonction membre:
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
};
Pour clarifier une question par chmike, par défaut std::lock_guard
et std::unique_lock
sont les mêmes. Donc, dans le cas ci-dessus, vous pouvez remplacer std::lock_guard
par std::unique_lock
. Cependant, std::unique_lock
pourrait avoir un peu plus de frais généraux.
Notez que ces jours-ci, il faut utiliser à la std::scoped_lock
place de std::lock_guard
.
Stephan Dollberg
la source
std::lock_guard
suffit pour votre cas A, vous devez l'utiliser. Non seulement cela évite les frais généraux inutiles, mais montre également l'intention du lecteur que vous ne déverrouillerez jamais cette garde.unique_lock
est susceptible d'être éclipsé par le coût du verrouillage et du déverrouillage du mutex (si le compilateur n'a pas optimisé ce surcoût, ce qui pourrait être possible).So for usecase B you definitely need a std::unique_lock for the condition variable
- oui mais seulement dans le thread quicv.wait()
s, car cette méthode libère atomiquement le mutex. Dans l'autre thread où vous mettez à jour les variables partagées, puis appelezcv.notify_one()
, un simplelock_guard
suffit pour verrouiller le mutex dans la portée ... à moins que vous ne fassiez quelque chose de plus élaboré que je ne peux pas imaginer! par exemple en.cppreference.com/w/cpp/thread/condition_variable - fonctionne pour moi :)lock_guard
etunique_lock
sont à peu près la même chose;lock_guard
est une version restreinte avec une interface limitée.A
lock_guard
détient toujours un verrou de sa construction à sa destruction. Ununique_lock
peut être créé sans verrouillage immédiat, peut se déverrouiller à tout moment de son existence et peut transférer la propriété du verrou d'une instance à une autre.Donc, vous utilisez toujours
lock_guard
, sauf si vous avez besoin des capacités deunique_lock
. A acondition_variable
besoin d'ununique_lock
.la source
A condition_variable needs a unique_lock.
- oui mais seulement duwait()
côté ing, comme expliqué dans mon commentaire à inf.À utiliser
lock_guard
sauf si vous devez être en mesure de manuellementunlock
le mutex entre les deux sans détruire lelock
.En particulier,
condition_variable
déverrouille son mutex lorsqu'il s'endort lors des appels àwait
. C'est pourquoi unlock_guard
n'est pas suffisant ici.la source
lock_guard
et le déverrouiller, brisant ainsi temporairement l'invariant de classe du garde. Même si cela se produit invisible pour l'utilisateur, je considère que c'est une raison légitime de ne pas autoriser l'utilisation delock_guard
dans ce cas.lock_guard
ne permet pas du tout de récupérer le mutex sous-jacent. Il s'agit d'une limitation délibérée pour permettre un raisonnement plus simple sur le code qui utiliselock_guard
par opposition au code qui utilise aunique_lock
. La seule façon d'atteindre ce que vous demandez est de rompre délibérément l'encapsulation de lalock_guard
classe et d'exposer son implémentation à une classe différente (dans ce cas, lacondition_variable
). Il s'agit d'un prix difficile à payer pour l'avantage discutable de l'utilisateur d'une variable de condition de ne pas avoir à se rappeler la différence entre les deux types de verrouillage.condition_variable_any.wait
fonctionnerait avec unlock_guard
? La norme exige que le type de verrouillage fourni réponde à l'BasicLockable
exigence (§30.5.2), ce quilock_guard
n'est pas le cas. Seul son mutex sous-jacent le fait, mais pour des raisons que j'ai soulignées plus tôt, l'interface delock_guard
ne fournit pas d'accès au mutex.Il y a certaines choses communes entre
lock_guard
etunique_lock
et certaines différences.Mais dans le contexte de la question posée, le compilateur n'autorise pas l'utilisation d'une
lock_guard
combinaison avec une variable de condition, car lorsqu'un thread appelle attendre une variable de condition, le mutex est déverrouillé automatiquement et lorsque d'autres threads / threads notifient et le thread actuel est invoqué (sort de l'attente), le verrou est racheté.Ce phénomène est contraire au principe de
lock_guard
.lock_guard
ne peut être construit qu'une seule fois et détruit une seule fois.Par conséquent,
lock_guard
ne peut pas être utilisé en combinaison avec une variable de condition, mais ununique_lock
peut l'être (car ilunique_lock
peut être verrouillé et déverrouillé plusieurs fois).la source
he compiler does not allow using a lock_guard in combination with a condition variable
C'est faux. Il a certainement ne permet et fonctionne parfaitement aveclock_guard
lenotify()
côté ing. Seul lewait()
côté int nécessite ununique_lock
, car ilwait()
doit libérer le verrou tout en vérifiant l'état.Ce ne sont pas vraiment les mêmes mutex,
lock_guard<muType>
a presque la même chosestd::mutex
, à la différence près que sa durée de vie se termine à la fin de la portée (appelé D-tor), donc une définition claire de ces deux mutex:Et
Voici un exemple d'implémentation:
Dans cet exemple, j'ai utilisé le
unique_lock<muType>
aveccondition variable
la source
Comme cela a été mentionné par d'autres, std :: unique_lock suit l'état verrouillé du mutex, vous pouvez donc différer le verrouillage jusqu'à la fin de la construction du verrou et le déverrouiller avant sa destruction. std :: lock_guard ne le permet pas.
Il ne semble pas y avoir de raison pour que les fonctions d'attente std :: condition_variable ne prennent pas aussi bien un lock_guard qu'un unique_lock, car chaque fois qu'une attente se termine (pour une raison quelconque), le mutex est automatiquement réacquis afin que cela ne cause aucune violation sémantique. Cependant, selon la norme, pour utiliser un std :: lock_guard avec une variable de condition, vous devez utiliser un std :: condition_variable_any au lieu de std :: condition_variable.
Edit : supprimé "L'utilisation de l'interface pthreads std :: condition_variable et std :: condition_variable_any devraient être identiques". En regardant la mise en œuvre de gcc:
la source