std:: scoped_lock
|
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
|
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
|
(C++11)
|
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) |