我有以下代码,来自https://en.cppreference.com/w/cpp/thread/unique_lock。但是,在打印输出时,我看到了一些意想不到的结果,并希望得到一些解释。
代码是:
#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();
}
我的期望:
- acc1 将使用 num_things=100 进行初始化,而 acc2 将使用 num_things=50 进行初始化。
- 假设线程 t1 首先运行,它获得互斥体 m,带有 2 个锁。一旦锁被锁定,并且可以将 num_things 分配给 num=10
- 完成后,它将按顺序打印 from.num_things = 110 和 to.numthings = 60。先“从”,再“到”。
- thread1 完成代码的关键部分,包装器 unique_lock 调用其析构函数,这基本上解锁了互斥锁。
这是我不明白的。
我希望先解锁 lock1 填充,然后再解锁 lock2。然后线程 t2 以相同的顺序获取互斥锁并先锁定 lock1,然后锁定 lock2。它还将按顺序运行关键代码直到 cout。
线程 t2 将从 t1 获取全局 acc1.num_things = 110 和 acc2.num_things = 60。
我希望 t2 将首先打印 from.num_things = 115,然后打印 to.numthings = 65。
然而,经过无数次的尝试,我总是得到相反的顺序。这就是我的困惑。