c++ - std:: lock_guard o std:: scoped_lock?
multithreading locking (3)
C ++ 17 introdujo una nueva clase de bloqueo llamada
std::scoped_lock
.
A juzgar por la documentación, se parece a la clase
std::lock_guard
ya existente.
¿Cuál es la diferencia y cuándo debo usarla?
Aquí hay una muestra y una cita de C ++ Concurrency in Action :
friend void swap(X& lhs, X& rhs)
{
if (&lhs == & rhs)
return;
std::lock(lhs.m, rhs.m);
std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
swap(lhs.some_detail, rhs.some_detail);
}
vs.
friend void swap(X& lhs, X& rhs)
{
if (&lhs == &rhs)
return;
std::scoped_lock guard(lhs.m, rhs.m);
swap(lhs.some_detail, rhs.some_detail);
}
La existencia de
std::scoped_lock
significa que la mayoría de los casos en los que habría utilizadostd::lock
antes de c ++ 17 ahora se pueden escribir usandostd::scoped_lock
, con menos potencial de errores, lo que solo puede ser un buen ¡cosa!
La única e importante diferencia es que
std::scoped_lock
tiene un constructor variable que toma más de un mutex.
Esto permite bloquear múltiples mutexes en un punto muerto evitando la forma como si se usara
std::lock
.
{
// safely locked as if using std::lock
std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);
}
Anteriormente, tenía que bailar un poco para bloquear múltiples mutexes de manera segura usando
std::lock
como se explica en
esta respuesta
.
La adición del bloqueo de alcance hace que sea más fácil de usar y evita los errores relacionados.
Puede considerar
std::lock_guard
desuso.
El caso de argumento único de
std::scoped_lock
se puede implementar como una especialización y no tiene que temer sobre posibles problemas de rendimiento.
GCC 7 ya tiene soporte para
std::scoped_lock
que se puede ver
here
.
Para obtener más información, puede leer el documento estándar.
scoped_lock
es una versión estrictamente superior de
lock_guard
que bloquea un número arbitrario de mutexes a la vez (usando el mismo algoritmo de evitación de bloqueo que
std::lock
).
En el nuevo código, solo debe usar
scoped_lock
.
La única razón por la que todavía existe
lock_guard
es por compatibilidad.
No se puede eliminar simplemente porque se usa en el código actual.
Además, resultó indeseable cambiar su definición (de unaria a variadic), porque también es un cambio observable y, por lo tanto, rompedor (pero por razones algo técnicas).