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
Definido en el encabezado <mutex>
template < class Lockable1, class Lockable2, class ... LockableN >
void lock ( Lockable1 & lock1, Lockable2 & lock2, LockableN & ... lockn ) ;
(desde C++11)

Bloquea los objetos Lockable dados lock1 , lock2 , ... , lockn utilizando un algoritmo de prevención de interbloqueos para evitar el deadlock.

Los objetos están bloqueados por una serie no especificada de llamadas a lock , try_lock , y unlock . Si una llamada a lock o unlock resulta en una excepción, unlock es llamado para cualquier objeto bloqueado antes de relanzarla.

Contenidos

Parámetros

lock1, lock2, ... , lockn - los Lockable objetos a bloquear

Valor de retorno

(ninguno)

Notas

Boost proporciona una versión de esta función que toma una secuencia de Lockable objetos definidos por un par de iteradores.

std::scoped_lock ofrece un RAII wrapper para esta función, y generalmente se prefiere sobre una llamada directa a std::lock .

Ejemplo

El siguiente ejemplo utiliza std::lock para bloquear pares de mutexes sin interbloqueo.

#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 = "Empleado " + id + " tiene compañeros de almuerzo: ";
        for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
            ret += partner + (--n ? ", " : "");
        return ret;
    }
};
void send_mail(Employee&, Employee&)
{
    // Simular una operación de mensajería que consume tiempo
    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 << " y " << e2.id << " están esperando por bloqueos" << std::endl;
    }
    // Use std::lock to acquire two locks without worrying about 
    // otras llamadas a assign_lunch_partrier nos bloquean
    {
        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);
    // Código equivalente (si se necesitan unique_locks, por ejemplo para variables de condición)
    //  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);
    // Superior solution available in C++17
    //  std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " y " << e2.id << " obtuvo bloqueos" << 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");
    // Asignar en hilos paralelos porque enviar correo a usuarios sobre asignaciones de almuerzo
    // toma mucho tiempo
    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';
}

Salida posible:

Alice y Bob están esperando por locks
Alice y Bob obtuvieron locks
Christina y Bob están esperando por locks
Christina y Bob obtuvieron locks
Christina y Alice están esperando por locks
Dave y Bob están esperando por locks
Dave y Bob obtuvieron locks
Christina y Alice obtuvieron locks
Empleado Alice tiene compañeros de almuerzo: Bob, Christina 
Empleado Bob tiene compañeros de almuerzo: Alice, Christina, Dave 
Empleado Christina tiene compañeros de almuerzo: Bob, Alice 
Empleado Dave tiene compañeros de almuerzo: Bob

Véase también

implementa un contenedor de propiedad de mutex móvil
(plantilla de clase)
(C++11)
intenta obtener la propiedad de mutexes mediante llamadas repetidas a try_lock
(plantilla de función)
contenedor RAII que evita interbloqueos para múltiples mutexes
(plantilla de clase)