std::lock
Определено в заголовочном файле <mutex> | ||
|---|---|---|
template< class Lockable1, class Lockable2, class... LockableN > void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn ); | (начиная с C++11) |
Блокирует заданные объекты Lockable lock1, lock2, ..., lockn с помощью алгоритма предотвращения взаимной блокировки.
Объекты блокируются с помощью неопределённой последовательности вызовов lock, try_lock и unlock. Если вызов lock или unlock приводит к исключению, для всех заблокированных объектов вызывается unlock, после чего исключение повторно генерируется.
Параметры
| lock1, lock2, ... , lockn | - | объекты Lockable, которые необходимо заблокировать |
Возвращаемое значение
(отсутствует)
Примечания
Boost предоставляет версию этой функции, которая принимает последовательность объектов Lockable, заданную парой итераторов.
std::scoped_lock предоставляет для этой функции обёртку RAII и, как правило, предпочтительнее прямого вызова std::lock.
Пример
В следующем примере std::lock используется для блокировки пар мьютексов без взаимной блокировки.
#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 = "Employee " + id + " has lunch partners: ";
for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
ret += partner + (--n ? ", " : "");
return ret;
}
};
void send_mail(Employee&, Employee&)
{
// Simulate a time-consuming messaging operation
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 << " and " << e2.id << " are waiting for locks" << std::endl;
}
// Use std::lock to acquire two locks without worrying about
// other calls to assign_lunch_partner deadlocking us
{
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);
// Equivalent code (if unique_locks are needed, e.g. for condition variables)
// 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 << " and " << e2.id << " got locks" << 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");
// Assign in parallel threads because mailing users about lunch assignments
// takes a long time
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';
}
Возможный вывод:
Alice and Bob are waiting for locks Alice and Bob got locks Christina and Bob are waiting for locks Christina and Bob got locks Christina and Alice are waiting for locks Dave and Bob are waiting for locks Dave and Bob got locks Christina and Alice got locks Employee Alice has lunch partners: Bob, Christina Employee Bob has lunch partners: Alice, Christina, Dave Employee Christina has lunch partners: Bob, Alice Employee Dave has lunch partners: Bob
См. также
|
(C++11) | реализует перемещаемую обёртку владения мьютексом (шаблон класса) |
|
(C++11) | пытается получить владение мьютексами с помощью повторных вызовов try_lock (шаблон функции) |
|
(C++17) | обёртка RAII для нескольких мьютексов, предотвращающая взаимную блокировку (шаблон класса) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/thread/lock