|
|
Defined in header <mutex> | ||
template<class Lockable1,class Lockable2,class...LockableN> void lock( Lockable1& lock1, Lockable2& lock2, LockableN&...lockn); | (since C++11) | |
Locks the givenLockable objectslock1,lock2,...
,lockn using a deadlock avoidance algorithm to avoid deadlock.
The objects are locked by an unspecified series of calls tolock
,try_lock
, andunlock
. If a call tolock
orunlock
results in an exception,unlock
is called for any locked objects before rethrowing.
Contents |
lock1, lock2, ... , lockn | - | theLockable objects to lock |
(none)
Boost provides a version of this function that takes a sequence ofLockable objects defined by a pair of iterators.
std::scoped_lock offers aRAII wrapper for this function, and is generally preferred to a naked call tostd::lock
.
The following example usesstd::lock
to lock pairs of mutexes without deadlock.
#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()};constauto& partner: lunch_partners) ret+= partner+(--n?", ":"");return ret;}}; void send_mail(Employee&, Employee&){// Simulate a time-consuming messaging operationstd::this_thread::sleep_for(std::chrono::milliseconds(696));} void assign_lunch_partner(Employee& e1, Employee& e2){staticstd::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 timestd::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';}
Possible output:
Alice and Bob are waiting for locksAlice and Bob got locksChristina and Bob are waiting for locksChristina and Bob got locksChristina and Alice are waiting for locksDave and Bob are waiting for locksDave and Bob got locksChristina and Alice got locksEmployee 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) | implements movable mutex ownership wrapper (class template)[edit] |
(C++11) | attempts to obtain ownership of mutexes via repeated calls totry_lock (function template)[edit] |
(C++17) | deadlock-avoiding RAII wrapper for multiple mutexes (class template)[edit] |