[英]what does unique_lock mean when a single thread acquire 2 unique_lock of the same mutex?
我有以下代码,来自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();
}
我的期望:
这是我不明白的地方。
我希望先解锁 lock1 填充,然后再解锁 lock2。 线程 t2 然后以相同的顺序获取互斥锁并先锁定 lock1,然后锁定 2。 它还将按顺序运行关键代码直到 cout。
线程 t2 将从 t1 中获取全局 acc1.num_things = 110 和 acc2.num_things = 60。
我希望 t2 将首先打印 from.num_things = 115,然后打印 to.numthings = 65。
然而,经过无数次的试验,我总是得到相反的顺序。 这就是我的困惑。
我希望先解锁 lock1 填充,然后再解锁 lock2。
不,反之亦然。 在您的函数中,首先构造lock1
,然后lock2
。 因此,当函数返回时, lock2
被销毁,然后lock1
,因此lock2
的析构函数在lock1
的析构函数之前释放其锁。
std::lock
设法获取多个锁的实际顺序与锁如何被销毁以及释放它们对各自互斥锁的所有权无关。 这样做仍然遵循正常的 C++ 规则。
说线程 t1 首先运行,
无论如何,您无法保证这一点。 在上面的代码中, t2
完全有可能首先进入函数并获取互斥锁上的锁。 而且,也完全有可能每次运行这个程序时,您都会得到不同的结果, t1
和t2
随机赢得比赛。
在不涉及技术上的笨拙的情况下,C++ 唯一能保证的是std::thread
在线程函数在新的执行线程中被调用之前被完全构造。 您无法保证在一个接一个地创建两个执行线程时,第一个将调用其函数并在第二个执行线程执行相同操作之前运行线程函数的任意部分。
所以完全有可能t2
偶尔会得到锁上的第一个 dib。 或者,总是。 试图控制跨执行线程的事件的相对顺序比您想象的要困难得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.