4

我想知道当你移动一个unique_lock持有 a 的 a时会发生什么recursive_mutex

具体来说,我正在查看这段代码:

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!
}

这个示例代码的输出让我很惊讶。in main()怎么unique_lock知道线程释放了互斥锁?这是真的吗?

4

1 回答 1

7

您似乎将一些神奇的属性归因于unique_lock. 它没有,这是一个非常简单的类。它有两个数据成员,Mutex* pmbool owns(仅用于说明的成员名称)。lock()很简单pm->lock(); owns = true;unlock确实如此pm->unlock(); owns = false;。析构函数是if (owns) unlock();. 将构造函数复制到这两个成员上,并相应地将它们设置为原始的nullptrfalseowns_lock()返回owns成员的值。

所有线程同步的魔力都在互斥锁本身及其lock()方法unlock()中。unique_lock只是围绕它的一个薄包装。

现在,作为先决条件,调用的线程mutex.unlock()必须持有互斥体(意味着该线程先前已调用lock()过它),否则程序会表现出未定义的行为。无论您是unlock显式调用还是欺骗某些助手(例如unique_lock为您调用它)都是如此。

鉴于这一切,将一个unique_lock实例移动到另一个线程只是此后不久触发未定义行为的一种方法。没有好处。

于 2016-07-18T17:41:53.623 回答