259 votes

std::lock_guard ou std::scoped_lock ?

C++17 a introduit une nouvelle classe de verrouillage appelée std::scoped_lock .

À en juger par la documentation, il semble similaire à l'outil de gestion de l'information déjà existant. std::lock_guard clase.

Quelle est la différence et quand dois-je l'utiliser ?

198voto

Kerrek SB Points 194696

El scoped_lock est une version strictement supérieure de lock_guard qui verrouille un nombre arbitraire de mutex en une seule fois (en utilisant le même algorithme d'évitement des blocages que celui utilisé par la méthode std::lock ). Dans un nouveau code, vous ne devriez jamais utiliser scoped_lock .

La seule raison lock_guard existe encore, c'est pour la compatibilité. Il ne pouvait pas simplement être supprimé, car il est utilisé dans le code actuel. De plus, il s'est avéré indésirable de changer sa définition (d'unaire à variadique), car c'est aussi un changement observable, et donc cassant (mais pour des raisons un peu techniques).

14 votes

De plus, grâce à la déduction des arguments des modèles de classe, il n'est même pas nécessaire d'énumérer les types de verrouillages.

3 votes

@NicolBolas : C'est vrai, mais cela s'applique aussi à lock_guard . Mais cela rend certainement les classes de garde un peu plus faciles à utiliser.

11 votes

Scoped_lock n'existe qu'en C++17

181voto

Howard Hinnant Points 59526

Réponse tardive, et surtout en réponse à :

Vous pouvez envisager std::lock_guard déprécié.

Pour le cas courant où l'on a besoin de verrouiller exactement un mutex, std::lock_guard a une API qui est un peu plus sûre à utiliser que celle de scoped_lock .

Par exemple :

{
   std::scoped_lock lock;  // protect this block
   ...
}

L'extrait ci-dessus est probablement une erreur d'exécution accidentelle car il compile et ne fait absolument rien. Le codeur voulait probablement dire :

{
   std::scoped_lock lock{mut};  // protect this block
   ...
}

Maintenant il se verrouille/déverrouille mut .

Si lock_guard a été utilisé dans les deux exemples ci-dessus à la place, le premier exemple est une erreur de compilation au lieu d'une erreur d'exécution, et le second exemple a une fonctionnalité identique à la version qui utilise la fonction scoped_lock .

Mon conseil est donc d'utiliser l'outil le plus simple pour le travail :

  1. lock_guard si vous avez besoin de verrouiller exactement 1 mutex pour une portée entière.

  2. scoped_lock si vous avez besoin de verrouiller un nombre de mutex qui n'est pas exactement 1.

  3. unique_lock si vous avez besoin de déverrouiller dans le cadre du bloc (ce qui inclut l'utilisation avec un bloc condition_variable ).

Ce conseil hace no impliquent que scoped_lock devrait être redessiné pour ne pas accepter 0 mutex. Il existe des cas d'utilisation valables pour lesquels il est souhaitable que scoped_lock pour accepter des paquets de paramètres de modèles variadiques qui peuvent être vides. Et le cas vide devrait no verrouiller quoi que ce soit.

Et c'est pourquoi lock_guard n'est pas déprécié. scoped_lock y unique_lock peut être un sur-ensemble de la fonctionnalité de lock_guard mais ce fait est une arme à double tranchant. Parfois, il est tout aussi important de savoir ce qu'un type ne le fera pas do (construction par défaut dans ce cas).

143voto

bamboon Points 7089

La seule et importante différence est que std::scoped_lock a un constructeur variadique prenant plus d'un mutex. Cela permet de verrouiller plusieurs mutex de manière à éviter les blocages comme si std::lock ont été utilisés.

{
    // safely locked as if using std::lock
    std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);     
}

Auparavant, vous deviez faire une petite danse pour verrouiller plusieurs mutex de manière sûre en utilisant std::lock comme expliqué cette réponse .

L'ajout du verrouillage de la portée facilite l'utilisation et évite les erreurs qui y sont liées. Vous pouvez considérer std::lock_guard déprécié. Le cas de l'argument unique de std::scoped_lock peut être implémenté en tant que spécialisation et vous n'avez donc pas à craindre d'éventuels problèmes de performance.

Le GCC 7 prend déjà en charge std::scoped_lock qui peut être vu aquí .

Pour plus d'informations, vous pouvez lire le papier standard

11 votes

Vous avez répondu à votre propre question après seulement 10 minutes. Vous ne saviez vraiment pas ?

36 votes

Walter, je l'ai fait. stackoverflow.blog/2011/07/01/

0 votes

@Ruslan pas sûr de ce que vous voulez dire. Il n'y a pas eu de délai de 10 minutes. Lorsque vous créez une question, vous pouvez déjà fournir la réponse.

21voto

陳 力 Points 1690

Voici un échantillon et une citation de C++ Concurrence en action :

friend void swap(X& lhs, X& rhs)
{
    if (&lhs == & rhs)
        return;
    std::lock(lhs.m, rhs.m);
    std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
    std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
    swap(lhs.some_detail, rhs.some_detail);
}

vs.

friend void swap(X& lhs, X& rhs)
{
    if (&lhs == &rhs)
        return;
    std::scoped_lock guard(lhs.m, rhs.m);
    swap(lhs.some_detail, rhs.some_detail);
}

L'existence de std::scoped_lock signifie que la plupart des cas où vous auriez utilisé std::lock antérieures à c++17 peuvent maintenant être écrites en utilisant std::scoped_lock Il y a moins de risques d'erreurs, ce qui ne peut être qu'une bonne chose !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X