2015-10-13 43 views
1

我读的书“C++并发在行动”,并有关于在上市6.1使用的互斥体的一些问题,代码片段如下:为什么C++在行动listing_6.1并发不使用std :: recursive_mutex

void pop(T& value) 
{ 
    std::lock_guard<std::mutex> lock(m); 
    if(data.empty()) throw empty_stack(); 
    value=std::move(data.top()); 
    data.pop(); 
} 
bool empty() const 
{ 
    std::lock_guard<std::mutex> lock(m); 
    return data.empty(); 
} 

pop方法锁定互斥锁,然后调用空互斥锁。但互斥量不是递归互斥量,代码正常工作。所以我怀疑std::mutexstd::recursive_mutex之间的实际差异是什么。

回答

4

它呼吁data.empty()这似乎是从数据成员的函数。与您展示的empty功能不一样。

如果是这样,这将是一个递归调用

bool empty() const 
{ 
    std::lock_guard<std::mutex> lock(m); 
    return data.empty(); 
} 

,没有什么会工作。

+0

对不起,我错过了我的疏忽真正的空洞,谢谢! – vmcloud

3

好吧,recursive_mutex是...递归函数!

在某些操作系统中,两次锁定相同的互斥锁可能会导致系统错误(其中,锁可能被释放,应用程序可能会崩溃,实际上可能会发生各种奇怪和未定义的行为)。

看看这个(傻例子)

void recursivePusher(int x){ 
    if (x>10){ 
    return; 
    } 

    std::lock_guard<std::mutex> lock(m); 
    queue.push(x); 
    recursivePusher(x+1); 

} 

此功能recursivly增量x并将其推入一些共享queue。我们在上面讨论过的 - 同一个锁可能不会被相同的线程锁定两次,但我们确实需要确保共享队列不会被多线程线程改变。

一个简单的解决方案是将递归函数外的位置移动,但如果我们不能这样做会发生什么?如果被调用的函数是唯一可以锁定共享资源的函数,会发生什么情况?

例如,我的调用函数可能看起来像这样:

switch(option){ 

case case1: recursivly_manipulate_shared_array(); break; 
case case2: recursivly_manipulate_shared_queue(); break; 
case case3: recursivly_manipulate_shared_map(); break; 

} 

ofcourse,你不会锁定所有三个(shred_Array,shared_map,shared_queue)只为其中一人将被改变。

的解决方案是使用std::shared_mutex

void recursivePusher(int x){ 
    if (x>10){ 
    return; 
    } 

    std::lock_guard<std::recursive_mutex> lock(m); 
    queue.push(x); 
    recursivePusher(x+1); 

} 

如果同一线程并不需要锁定互斥recursivly它应该在你的榜样使用常规std::mutex,等等。

PS。在你的片段中,emptyT::empty不一样。 致电data.empty()不会拨打empty recursivley。

相关问题