2016-07-18 65 views
3

我想知道当您移动包含recursive_mutexunique_lock时会发生什么。将unique_lock <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! 
} 

此示例代码的输出让我吃惊不少。 main()中的unique_lock如何知道线程释放了互斥锁?这是真的吗?

+3

目前尚不清楚你会发现令人惊讶的事情。 'unique_lock'中有一个简单的布尔成员,它的'owns_lock()'返回,并且通过移动构造函数以可预测和记录的方式移动。 'owns_lock()'不会触及底层互斥体。话虽如此,你的程序展现出未定义的行为:当工作线程上'unique_lock'被销毁时,它调用'g_mutex.unlock()',但工作线程不会在'g_mutex'(这是一个pre - unlock()''的必要条件)。 –

+0

@IgorTandetnik谢谢。所以不可能在线程之间移动'recursive_mutex'的所有权?如果互斥量不是递归会怎么样?将unique_lock移动到所有者线程是否真的会移动? –

+3

在线程之间移动'unique_lock'确实对你没有任何好处。意识到'unique_lock'只不过是一个'互斥体*'指针和一个'bool拥有'标志 - 没有黑魔法。移动构造器简单地移动该指针和布尔值。在不同于调用'my_mutex.lock()'的线程上调用'my_mutex.unlock()'会展示未定义的行为,无论是通过欺骗'unique_lock'来明确或间接完成。所有互斥口味都是如此。 –

回答

3

您似乎将某些魔法属性归于unique_lock。它没有,这是一个非常简单的课程。它有两个数据成员,Mutex* pmbool owns(仅显示会员名称)。 lock()简单地为pm->lock(); owns = true;unlockpm->unlock(); owns = false;。破坏者是if (owns) unlock();。将构造函数副本移动到两个成员上,并相应地将它们的原始位置设置为nullptrfalseowns_lock()返回值为owns的成员。

所有的线程同步魔法都在互斥量本身,以及它的lock()unlock()方法。 unique_lock仅仅是一个薄薄的包装纸。

现在,作为先决条件,调用mutex.unlock()的线程必须持有该互斥锁(意味着该线程先前已在其上调用lock()),否则该程序会显示未定义的行为。无论你明确地致电unlock,还是怂恿像unique_lock这样的助手为你调用它,情况都是如此。根据所有这些,将unique_lock实例移动到另一个线程仅仅是此后不久触发未定义行为的配方;没有好处。

相关问题