将 unique_lock<recursive_mutex> 移动到另一个线程
Moving a unique_lock<recursive_mutex> to another thread
我想知道当你移动一个包含 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!
}
这个示例代码的输出让我很惊讶。 main()中的unique_lock
怎么知道线程释放了互斥体呢?是真的吗?
您似乎将某些魔法属性归于 unique_lock
。没有,很简单class。它有两个数据成员,Mutex* pm
和 bool owns
(成员名称仅供说明)。 lock()
就是 pm->lock(); owns = true;
,而 unlock
就是 pm->unlock(); owns = false;
。析构函数是 if (owns) unlock();
。 Move constructor 复制了这两个成员,并将它们在原来的 nullptr
和 false
中相应地设置。 owns_lock()
returns owns
成员的值。
所有线程同步的魔力都在互斥锁本身及其 lock()
和 unlock()
方法中。 unique_lock
只是它的薄包装。
现在,作为先决条件,调用 mutex.unlock()
的线程必须持有互斥量(也就是说,该线程之前已对其调用 lock()
),否则程序会出现未定义的行为。无论您是显式调用 unlock
,还是欺骗像 unique_lock
这样的助手来为您调用它,都是如此。
鉴于这一切,将一个 unique_lock
实例移到另一个线程只是此后不久触发未定义行为的一种方法;没有上升空间。
我想知道当你移动一个包含 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!
}
这个示例代码的输出让我很惊讶。 main()中的unique_lock
怎么知道线程释放了互斥体呢?是真的吗?
您似乎将某些魔法属性归于 unique_lock
。没有,很简单class。它有两个数据成员,Mutex* pm
和 bool owns
(成员名称仅供说明)。 lock()
就是 pm->lock(); owns = true;
,而 unlock
就是 pm->unlock(); owns = false;
。析构函数是 if (owns) unlock();
。 Move constructor 复制了这两个成员,并将它们在原来的 nullptr
和 false
中相应地设置。 owns_lock()
returns owns
成员的值。
所有线程同步的魔力都在互斥锁本身及其 lock()
和 unlock()
方法中。 unique_lock
只是它的薄包装。
现在,作为先决条件,调用 mutex.unlock()
的线程必须持有互斥量(也就是说,该线程之前已对其调用 lock()
),否则程序会出现未定义的行为。无论您是显式调用 unlock
,还是欺骗像 unique_lock
这样的助手来为您调用它,都是如此。
鉴于这一切,将一个 unique_lock
实例移到另一个线程只是此后不久触发未定义行为的一种方法;没有上升空间。