#include <iostream>
#include <mutex>
#include <thread>
#define SOL1
struct Box {
explicit Box( int num ) : num_things {num} {}
int num_things;
std::mutex m;
};
void transfer( Box & from, Box & to, int num )
{
#ifdef SOL1
// don't actually take the locks yet
std::unique_lock<std::mutex> lock1( from.m, std::defer_lock );
std::unique_lock<std::mutex> lock2( to.m, std::defer_lock );
// do some work here - mutexes are unlocked
std::lock( lock1, lock2 );
#endif
#ifdef SOL2
std::lock( from.m, to.m );
// make sure both already-locked mutexes are unlocked at the end of scope
std::lock_guard<std::mutex> lock1( from.m, std::adopt_lock );
std::lock_guard<std::mutex> lock2( to.m, std::adopt_lock );
#endif
// lock both unique_locks without deadlock
from.num_things -= num;
to.num_things += num;
// 'from.m' and 'to.m' mutexes unlocked in 'unique_lock' dtors
}
int main()
{
Box acc1( 100 );
Box acc2( 50 );
std::cout << "Box 1 = " << acc1.num_things << std::endl;
std::cout << "Box 2 = " << acc2.num_things << std::endl;
std::thread t1( transfer, std::ref( acc1 ), std::ref( acc2 ), 20 );
std::thread t2( transfer, std::ref( acc2 ), std::ref( acc1 ), 5 );
t1.join();
t2.join();
std::cout << "Box 1 = " << acc1.num_things << std::endl;
std::cout << "Box 2 = " << acc2.num_things << std::endl;
}