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
Definido en el encabezado <mutex>
template < class ... MutexTypes >
class scoped_lock ;
(desde C++17)

La clase scoped_lock es un envoltorio de mutex que proporciona un mecanismo conveniente estilo RAII para poseer cero o más mutexes durante la duración de un bloque de ámbito.

Cuando un objeto scoped_lock es creado, intenta tomar posesión de los mutex que se le proporcionan. Cuando el control sale del ámbito en el que el objeto scoped_lock fue creado, el scoped_lock es destruido y los mutex son liberados. Si se proporcionan varios mutex, se utiliza un algoritmo de prevención de interbloqueos como si fuera mediante std::lock .

La clase scoped_lock no es copiable.

Contenidos

Parámetros de plantilla

MutexTypes - los tipos de los mutexes a bloquear. Los tipos deben cumplir con los Lockable requisitos a menos que sizeof... ( MutexTypes ) == 1 , en cuyo caso el único tipo debe cumplir con BasicLockable

Tipos de miembros

Tipo de miembro Definición
mutex_type
(condicionalmente presente)

Si sizeof... ( MutexTypes ) == 1 , el tipo de miembro mutex_type es el mismo que Mutex , el único tipo en MutexTypes... . De lo contrario, no existe el miembro mutex_type .

Funciones miembro

construye un scoped_lock , opcionalmente bloqueando los mutex dados
(función miembro pública)
destruye el objeto scoped_lock , desbloquea los mutex subyacentes
(función miembro pública)
operator=
[deleted]
no asignable por copia
(función miembro pública)

Notas

Un error común de principiantes es "olvidar" darle un nombre a una variable scoped_lock , por ejemplo std :: scoped_lock ( mtx ) ; (que construye por defecto una variable scoped_lock llamada mtx ) o std :: scoped_lock { mtx } ; (que construye un objeto prvalue que se destruye inmediatamente), por lo tanto no se construye realmente un bloqueo que mantenga un mutex durante el resto del ámbito.

Macro de prueba de características Valor Estándar Característica
__cpp_lib_scoped_lock 201703L (C++17) std::scoped_lock

Ejemplo

El siguiente ejemplo utiliza std::scoped_lock para bloquear pares de mutexes sin interbloqueo y sigue el estilo 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 = "Empleado " + id + " tiene compañeros de almuerzo: ";
        for (int count{}; const auto& partner : lunch_partners)
            ret += (count++ ? ", " : "") + partner;
        return ret;
    }
};
void send_mail(Employee&, Employee&)
{
    // Simular una operación de mensajería que consume tiempo
    std::this_thread::sleep_for(1s);
}
void assign_lunch_partner(Employee& e1, Employee& e2)
{
    std::osyncstream synced_out(std::cout);
    synced_out << e1.id << " y " << e2.id << " están esperando por bloqueos" << std::endl;
    {
        // Use std::scoped_lock to acquire two locks without worrying about
        // otras llamadas a assign_lunch_partrier nos bloquean
        // y también proporciona un mecanismo conveniente de estilo RAII
        std::scoped_lock lock(e1.m, e2.m);
        // Código equivalente 1 (usando std::lock y 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);
        // Código equivalente 2 (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);
        synced_out << 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::osyncstream(std::cout) << alice.partners() << '\n'  
                                << bob.partners() << '\n'
                                << christina.partners() << '\n' 
                                << dave.partners() << '\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 Alice están esperando por locks
Dave y Bob están esperando por locks
Dave y Bob obtuvieron locks
Christina y Alice obtuvieron locks
Christina y Bob obtuvieron locks
Empleado Alice tiene compañeros de almuerzo: Bob, Christina
Empleado Bob tiene compañeros de almuerzo: Alice, Dave, Christina
Empleado Christina tiene compañeros de almuerzo: Alice, Bob
Empleado Dave tiene compañeros de almuerzo: Bob

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 2981 C++17 se proporcionó una guía de deducción redundante desde scoped_lock<MutexTypes...> eliminada

Véase también

implementa un contenedor de propiedad de mutex movible
(class template)
(C++11)
implementa un contenedor de propiedad de mutex estrictamente basado en ámbito
(class template)