web-dev-qa-db-fra.com

boost :: unique_lock vs boost :: lock_guard

Je ne comprends pas bien la différence entre ces deux classes de verrouillage. Dans la documentation boost, il est dit que boost::unique_lock Ne réalise pas automatiquement le verrouillage.

Cela signifie-t-il que la principale différence entre unique_lock Et lock_guard Est qu'avec unique_lock Nous devons appeler explicitement la fonction lock()?

58
Guillaume07

Répondez d'abord à votre question. Non, vous n'avez pas besoin d'appeler le verrouillage sur un unique_lock. Voir ci-dessous:

L'unique_lock est seulement une classe de verrouillage avec plus de fonctionnalités. Dans la plupart des cas, le lock_guard fera ce que vous voulez et sera suffisant.
L'unique_lock a plus de fonctionnalités à vous offrir. Par exemple, une attente chronométrée si vous avez besoin d'un délai d'attente ou si vous souhaitez reporter votre verrou à un point plus tard que la construction de l'objet. Cela dépend donc beaucoup de ce que vous voulez faire. BTW: Les extraits de code suivants font la même chose.

boost::mutex mutex;
boost::lock_guard<boost::mutex> lock(mutex);
boost::mutex mutex;
boost::unique_lock<boost::mutex> lock(mutex);

Le premier peut être utilisé pour synchroniser l'accès aux données, mais si vous souhaitez utiliser des variables de condition, vous devez opter pour le second.

60
mkaes

La réponse actuellement la mieux votée est bonne, mais elle n'a clarifié mon doute que lorsque j'ai creusé un peu plus profondément, j'ai donc décidé de partager avec des gens qui pourraient être dans le même bateau.

Tout d'abord les deux lock_guard et unique_lock suit le modèle RAII, dans le cas d'utilisation le plus simple, le verrou est acquis pendant la construction et déverrouillé automatiquement pendant la destruction. Si tel est votre cas d'utilisation, vous n'avez pas besoin de la flexibilité supplémentaire de unique_lock et lock_guard sera plus efficace.

La principale différence entre les deux est un unique_lock l'instance n'a pas besoin de toujours posséder le mutex auquel elle est associée dans lock_guard il possède le mutex. Ça signifie unique_lock devrait avoir un drapeau supplémentaire indiquant s'il possède le verrou et une autre méthode supplémentaire 'owns_lock ()' pour vérifier cela. Sachant cela, nous pouvons expliquer tous les avantages supplémentaires que ce drapeau apporte avec la surcharge de ces données supplémentaires à définir et à vérifier

  1. La serrure n'a pas besoin d'être prise juste à la construction, vous pouvez passer le drapeau std::defer_lock pendant sa construction pour garder le mutex déverrouillé pendant la construction.
  2. Nous pouvons le déverrouiller avant la fin de la fonction et ne pas nécessairement attendre que le destructeur la libère, ce qui peut être pratique.
  3. Vous pouvez transmettre la propriété du verrou à partir d'une fonction, c'est mobile et non copiable.
  4. Il peut être utilisé avec des variables conditionnelles car cela nécessite que mutex soit verrouillé, la condition vérifiée et déverrouillée en attendant une condition.
44
jayadev

Leur implémentation se trouve sous path .../boost/thread/locks.hpp - et ils sont assis l'un à côté de l'autre :) En résumé:

lock_guard est une courte classe utilitaire simple qui verrouille mutex dans le constructeur et déverrouille dans le destructeur, sans se soucier des détails.

nique_lock est un peu plus complexe, ajoutant pas mal de fonctionnalités - mais il se verrouille toujours automatiquement dans le constructeur. Il est appelé unique_lock car il introduit le concept de "propriété du verrou" (voir méthode owns_lock ()).

14
Mihails Strasuns

Si vous avez l'habitude de pthreads(3):

  • boost::mutex = pthread_mutex_*
  • boost::unique_lock = pthread_rwlock_* utilisé pour obtenir des verrous en écriture/exclusifs (c'est-à-dire pthread_rwlock_wrlock)
  • boost::shared_lock = pthread_rwlock_* utilisé pour obtenir des verrous en lecture/partagés (c'est-à-dire pthread_rwlock_rdlock)

Oui un boost::unique_lock et un boost::mutex fonctionne de la même manière, mais un boost::mutex est généralement un mutex plus léger à acquérir et à libérer. Cela dit, un shared_lock avec le verrou déjà acquis est plus rapide (et permet l'accès simultané), mais il est relativement coûteux d'obtenir un unique_lock.

Vous devez regarder sous les couvertures pour voir les détails de la mise en œuvre, mais c'est l'essentiel des différences prévues.


En parlant de performances: voici une comparaison modérément utile des latences:

http://www.eecs.berkeley.edu/%7Ercs/research/interactive_latency.html

Ce serait bien si je/quelqu'un pouvait comparer le coût relatif des différentes primitives pthread_ *, mais en dernier j'ai regardé, pthread_mutex_* était ~ 25us, tandis que pthread_rwlock_* était ~ 20-100us selon que le verrou en lecture avait déjà été acquis (~ 10us) ou non (~ 20us) ou un écrivain (~ 100us). Vous devrez comparer pour confirmer les chiffres actuels et je suis sûr que c'est très spécifique au système d'exploitation.

6
Sean

Je pense que unique_lock peut également être utilisé lorsque vous devez souligner la différence entre les verrous uniques et partagés.

1
Alexey Petrenko