Namespaces
Variants

std:: 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
lock
(C++11)
(C++11)
(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 Lockable1, class Lockable2, class ... LockableN >
void lock ( Lockable1 & lock1, Lockable2 & lock2, LockableN & ... lockn ) ;
(depuis C++11)

Verrouille les objets Lockable donnés lock1 , lock2 , ... , lockn en utilisant un algorithme d'évitement des interblocages pour prévenir les deadlocks.

Les objets sont verrouillés par une série non spécifiée d'appels à lock , try_lock , et unlock . Si un appel à lock ou unlock provoque une exception, unlock est appelé pour tous les objets verrouillés avant de relancer l'exception.

Table des matières

Paramètres

lock1, lock2, ... , lockn - les Lockable objets à verrouiller

Valeur de retour

(aucun)

Notes

Boost fournit une version de cette fonction qui prend une séquence d'objets Lockable définie par une paire d'itérateurs.

std::scoped_lock offre une RAII enveloppe pour cette fonction, et est généralement préféré à un appel direct à std::lock .

Exemple

L'exemple suivant utilise std::lock pour verrouiller des paires de mutex sans interblocage.

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
struct Employee
{
    Employee(std::string id) : id(id) {}
    std::string id;
    std::vector<std::string> lunch_partners;
    std::mutex m;
    std::string output() const
    {
        std::string ret = "Employé " + id + " a des partenaires de déjeuner: ";
        for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
            ret += partner + (--n ? ", " : "");
        return ret;
    }
};
void send_mail(Employee&, Employee&)
{
    // Simuler une opération de messagerie longue
    std::this_thread::sleep_for(std::chrono::milliseconds(696));
}
void assign_lunch_partner(Employee& e1, Employee& e2)
{
    static std::mutex io_mutex;
    {
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << e1.id << " et " << e2.id << " attendent des verrous" << std::endl;
    }
    // Utiliser std::lock pour acquérir deux verrous sans se soucier de 
    // autres appels à assign_lunch_partner nous bloquant
    {
        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 (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);
    // Solution supérieure disponible en C++17
    //  std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << 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::cout << alice.output() << '\n'
              << bob.output() << '\n'
              << christina.output() << '\n'
              << dave.output() << '\n';
}

Sortie possible :

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

Voir aussi

implémente un wrapper de propriété de mutex déplaçable
(modèle de classe)
(C++11)
tente d'obtenir la propriété des mutex via des appels répétés à try_lock
(modèle de fonction)
wrapper RAII évitant les interblocages pour plusieurs mutex
(modèle de classe)