I have the following code, which is from https://en.cppreference.com/w/cpp/thread/unique_lock. However, upon, printing the output, I see some unexpected result and would like some explaination.
The code is:
#include <mutex>
#include <thread>
#include <chrono>
#include <iostream>
struct Box {
explicit Box(int num) : num_things{num} {}
int num_things;
std::mutex m;
};
void transfer(Box &from, Box &to, int anotherNumber)
{
// 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);
// lock both unique_locks without deadlock
std::lock(lock1, lock2);
from.num_things += anotherNumber;
to.num_things += anotherNumber;
std::cout<<std::this_thread::get_id()<<" "<<from.num_things<<"\n";
std::cout<<std::this_thread::get_id()<<" "<<to.num_things<<"\n";
// 'from.m' and 'to.m' mutexes unlocked in 'unique_lock' dtors
}
int main()
{
Box acc1(100); //initialized acc1.num_things = 100
Box acc2(50); //initialized acc2.num_things = 50
std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);
t1.join();
t2.join();
}
My expectation:
- acc1 will be initialized with num_things=100, and acc2 with num_things=50.
- say thread t1 runs first, it acquire mutex m, with 2 locks. Once the locks are locked, and can assign num_things to num=10
- upon completion, it will print from.num_things = 110 and to.numthings = 60 in order. "from" first, then "to" later.
- thread1 finishes the critical section of the code, and wrapper unique_lock calls its destructor which basically unlock the mutex.
Here is what I don't understand.
I expected the lock1 fill be unlocked first, and lock2 later. Thread t2 then acquire the mutex in the same order and lock the lock1 first, then lock2. It will also runs the critical code sequentially up to cout.
Thread t2 will take the global acc1.num_things = 110 and acc2.num_things = 60 from t1.
I expect that t2 will print from.num_things = 115 first, then to.numthings = 65.
However, upon countless trial, I always get the reverse order. And that is my confusion.