我想知道当你移动一个持有recursive_mutex
的unique_lock
时会发生什么。
具体来说,我在看这段代码:
recursive_mutex g_mutex;
#define TRACE(msg) trace(__FUNCTION__, msg)
void trace(const char* function, const char* message)
{
cout << std::this_thread::get_id() << "\t" << function << "\t" << message << endl;
}
future<void> foo()
{
unique_lock<recursive_mutex> lock(g_mutex);
TRACE("Owns lock");
auto f = std::async(launch::async, [lock = move(lock)]{
TRACE("Entry");
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock!
this_thread::sleep_for(chrono::seconds(3));
});
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Doesn't own lock!
return f;
}
int main()
{
unique_lock<recursive_mutex> lock(g_mutex);
TRACE("Owns lock");
auto f = foo();
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock!
f.wait();
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock!
}
这段示例代码的输出让我感到非常惊讶。主函数中的
unique_lock
如何知道线程已经释放了互斥锁?这是真的吗?
unique_lock
中有一个简单的布尔成员,它返回owns_lock()
,并且移动构造函数以可预测和记载的方式将其移动。owns_lock()
不会触及底层互斥锁。话虽如此,您的程序表现出未定义的行为:当在工作线程上销毁unique_lock
时,它调用g_mutex.unlock()
,但工作线程没有持有g_mutex
的锁(这是unlock()
的前提条件)。 - Igor Tandetnikrecursive_mutex
的所有权是不可能的吗?如果互斥量不是递归的呢?将unique_lock
移动到所有者线程是否真的会移动所有权? - Mr. Andersonunique_lock
对象在不同线程之间移动对你没有任何好处。要意识到,unique_lock
实际上只是一个mutex*
指针和一个bool owns
标志 - 没有黑魔法。移动构造函数只是移动这个指针和布尔值。在调用了my_mutex.lock()
的线程不同于调用my_mutex.unlock()
的线程时,无论是直接调用还是通过欺骗unique_lock
来间接调用,都会导致未定义行为。这适用于所有类型的互斥锁。 - Igor Tandetnik