std::lock
De cppreference.com
<tbody>
</tbody>
| Definido en el archivo de 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 usando un algoritmo de evitación de bloqueo mutuo para evitar el bloqueo mutuo.
Los objetos se bloquean por una serie de llamadas no especificadas a lock, try_lock, y unlock. Si una llamada a lock o unlock resulta en una excepción, se llama a unlock por cualquiera de los objetos bloqueados antes de volver a lanzar.
Parámetros
| lock1, lock2, ... , lockn | - | Los objetos Lockable a bloquear. |
Valor de retorno
(none)
Notas
Boost proporciona una versión de esta función que toma una secuencia de objetos Lockable definidos por un par de iteradores.
std::scoped_lock ofrece un envoltorio RAII para esta función, y se prefiere generalmente a una llamada manifiesta a std::lock.
Ejemplo
El siguiente ejemplo utiliza a std::lock para bloquear pares de mutexes sin bloqueo mutuo.
Ejecuta este código
#include <mutex>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
#include <chrono>
#include <string>
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(a) " + id + " tiene compañeros para el almuerzo: ";
for( const auto& partner : lunch_partners )
ret += partner + " ";
return ret;
}
};
void send_mail(Employee &, Employee &)
{
// simular una operación de mensajeo de largo tiempo
std::this_thread::sleep_for(std::chrono::seconds(1));
}
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 << " and " << e2.id << " están a la espera de cerrojos" << std::endl;
}
// usar std::lock para adquirir dos cerrojos sin preocuparse de
// otras llamadas a assign_lunch_partner que nos bloqueen mutuamente
{
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 code (si se necesitan unique_locks, es decir, 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);
// Solución superior disponible en 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 << " obtuvieron cerrojos" << 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 ana("Ana"), beto("Beto"), cristina("Cristina"), david("David");
// asignar en hilos paralelos ya que enviar correo a usuarios sobre
// las asignaciones de los compañeros de almuerzo toma mucho tiempo
std::vector<std::thread> threads;
threads.emplace_back(assign_lunch_partner, std::ref(Ana), std::ref(Beto));
threads.emplace_back(assign_lunch_partner, std::ref(Cristina), std::ref(Beto));
threads.emplace_back(assign_lunch_partner, std::ref(Cristina), std::ref(Ana));
threads.emplace_back(assign_lunch_partner, std::ref(David), std::ref(Beto));
for (auto &thread : threads) thread.join();
std::cout << ana.output() << '\n' << beto.output() << '\n'
<< cristina.output() << '\n' << david.output() << '\n';
}
Posible salida:
Ana y Beto están a la espera de cerrojos
Ana y Beto obtuvieron cerrojos
Cristina y Beto están a la espera de cerrojos
Cristina y Beto obtuvieron cerrojos
Cristina y Ana están a la espera de cerrojos
Cristina y Ana obtuvieron cerrojos
David y Beto están a la espera de cerrojos
David y Beto obtuvieron cerrojos
Empleado(a) Ana tiene compañeros para el almuerzo: Beto Cristina
Empleado(a) Beto tiene compañeros para el almuerzo: Ana Cristina David
Empleado(a) Cristina tiene compañeros para el almuerzo: Beto Ana
Empleado(a) David tiene compañeros para el almuerzo: Beto
Véase también
(C++11) |
Intenta tomar posesión de los mutex mediante llamadas repetidas a try_lock. (plantilla de función) |
(C++17) |
Envoltorio RAII que evita bloqueo mutuo para múltiples mutex. (plantilla de clase) |