Namespaces
Variants

std:: scoped_lock

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
(C++11)
(C++11)
scoped_lock
(C++17)
(C++11)
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
Défini dans l'en-tête <mutex>
template < class ... MutexTypes >
class scoped_lock ;
(depuis C++17)

La classe scoped_lock est un wrapper de mutex qui fournit un mécanisme pratique de type RAII pour posséder zéro ou plusieurs mutex pendant la durée d'un bloc de portée.

Lorsqu'un objet scoped_lock est créé, il tente de prendre la possession des mutex qui lui sont donnés. Lorsque le contrôle quitte la portée dans laquelle l'objet scoped_lock a été créé, le scoped_lock est détruit et les mutex sont libérés. Si plusieurs mutex sont donnés, l'algorithme d'évitement des interblocages est utilisé comme par std::lock .

La classe scoped_lock n'est pas copiable.

Table des matières

Paramètres du modèle

MutexTypes - les types des mutex à verrouiller. Les types doivent satisfaire aux Lockable exigences, sauf si sizeof... ( MutexTypes ) == 1 , auquel cas le seul type doit satisfaire aux BasicLockable

Types membres

Type de membre Définition
mutex_type
(conditionnellement présent)

Si sizeof... ( MutexTypes ) == 1 , le type de membre mutex_type est identique à Mutex , le seul type dans MutexTypes... . Sinon, il n'y a pas de membre mutex_type .

Fonctions membres

construit un scoped_lock , verrouillant optionnellement les mutex donnés
(fonction membre publique)
détruit l'objet scoped_lock , déverrouille les mutex sous-jacents
(fonction membre publique)
operator=
[deleted]
non assignable par copie
(fonction membre publique)

Notes

Une erreur courante chez les débutants est d'« oublier » de donner un nom à une variable scoped_lock , par exemple std :: scoped_lock ( mtx ) ; (qui construit par défaut une variable scoped_lock nommée mtx ) ou std :: scoped_lock { mtx } ; (qui construit un objet prvalue immédiatement détruit), ne construisant ainsi pas réellement un verrou qui maintient un mutex pour le reste de la portée.

Macro de test de fonctionnalité Valeur Norme Fonctionnalité
__cpp_lib_scoped_lock 201703L (C++17) std::scoped_lock

Exemple

L'exemple suivant utilise std::scoped_lock pour verrouiller des paires de mutex sans interblocage et suit le style RAII.

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <syncstream>
#include <thread>
#include <vector>
using namespace std::chrono_literals;
struct Employee
{
    std::vector<std::string> lunch_partners;
    std::string id;
    std::mutex m;
    Employee(std::string id) : id(id) {}
    std::string partners() const
    {
        std::string ret = "Employé " + id + " a des partenaires de déjeuner: ";
        for (int count{}; const auto& partner : lunch_partners)
            ret += (count++ ? ", " : "") + partner;
        return ret;
    }
};
void send_mail(Employee&, Employee&)
{
    // Simuler une opération de messagerie longue
    std::this_thread::sleep_for(1s);
}
void assign_lunch_partner(Employee& e1, Employee& e2)
{
    std::osyncstream synced_out(std::cout);
    synced_out << e1.id << " et " << e2.id << " attendent des verrous" << std::endl;
    {
        // Utilisez std::scoped_lock pour acquérir deux verrous sans vous soucier de
        // autres appels à assign_lunch_partner nous bloquant
        // et il fournit également un mécanisme pratique de style RAII
        std::scoped_lock lock(e1.m, e2.m);
        // Code équivalent 1 (utilisant std::lock et std::lock_guard)
        // std::lock(e1.m, e2.m);
        // std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock);
        // std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock);
        // Code équivalent 2 (si des verrous uniques sont nécessaires, par exemple pour des variables de condition)
        // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock);
        // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock);
        // std::lock(lk1, lk2);
        synced_out << e1.id << " et " << e2.id << " a obtenu des verrous" << std::endl;
        e1.lunch_partners.push_back(e2.id);
        e2.lunch_partners.push_back(e1.id);
    }
    send_mail(e1, e2);
    send_mail(e2, e1);
}
int main()
{
    Employee alice("Alice"), bob("Bob"), christina("Christina"), dave("Dave");
    // Assigner en parallèle dans des threads car envoi d'emails aux utilisateurs concernant les affectations de déjeuner
    // prend beaucoup de temps
    std::vector<std::thread> threads;
    threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
    threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));
    for (auto& thread : threads)
        thread.join();
    std::osyncstream(std::cout) << alice.partenaires() << '\n'  
                                << bob.partenaires() << '\n'
                                << christina.partenaires() << '\n' 
                                << dave.partenaires() << '\n';
}

Sortie possible :

Alice et Bob attendent des verrous
Alice et Bob ont obtenu des verrous
Christina et Bob attendent des verrous
Christina et Alice attendent des verrous
Dave et Bob attendent des verrous
Dave et Bob ont obtenu des verrous
Christina et Alice ont obtenu des verrous
Christina et Bob ont obtenu des verrous
Employé Alice a des partenaires de déjeuner : Bob, Christina
Employé Bob a des partenaires de déjeuner : Alice, Dave, Christina
Employé Christina a des partenaires de déjeuner : Alice, Bob
Employé Dave a des partenaires de déjeuner : Bob

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR S'applique à Comportement publié Comportement corrigé
LWG 2981 C++17 le guide de déduction redondant de scoped_lock<MutexTypes...> était fourni supprimé

Voir aussi

implémente un wrapper de propriété de mutex déplaçable
(modèle de classe)
(C++11)
implémente un wrapper de propriété de mutex strictement basé sur la portée
(modèle de classe)