Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 线程安全堆栈C+中的潜在死锁+;_C++_Multithreading_Concurrency - Fatal编程技术网

C++ 线程安全堆栈C+中的潜在死锁+;

C++ 线程安全堆栈C+中的潜在死锁+;,c++,multithreading,concurrency,C++,Multithreading,Concurrency,在《Action中的并发性》一书中,有一个线程安全堆栈的实现,其中在输入pop()和empty()函数时获取/锁定互斥,如下所示: class threadsafe_stack { private: std::stack<T> data; mutable std::mutex m; public: //... void pop(T& value) { std::lock_guard<std::

在《Action中的并发性》一书中,有一个线程安全堆栈的实现,其中在输入pop()和empty()函数时获取/锁定互斥,如下所示:

class threadsafe_stack {
   private:
      std::stack<T> data;
      mutable std::mutex m;
   public:
      //...
      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();
      }
};
类线程安全\u堆栈{
私人:
std::堆栈数据;
可变std::mutexm;
公众:
//...
无效pop(T和值){
标准:锁和防护锁(m);
if(data.empty())抛出empty_stack();
value=std::move(data.top());
data.pop();
}
bool empty()常量{
标准:锁和防护锁(m);
返回data.empty();
}
};

我的问题是,当一个在进入pop()时获得锁的线程调用同样受互斥锁保护的empty()时,这段代码如何不陷入死锁?如果已经拥有互斥锁的线程调用lock(),这不是未定义的行为吗

如果
pop
调用
this->empty
,您就对了。除非锁定的互斥锁是递归的,否则通过std::lock\u guard两次锁定同一互斥锁是未定义的行为

从构造函数(示例代码中使用的构造函数)开始:

有效地调用m.lock()。如果m不是递归互斥体并且当前线程已经拥有m,则该行为是未定义的

为完整起见,还有第二个构造函数:

lock_guard( mutex_type& m, std::adopt_lock_t t );
哪个

获取互斥锁m的所有权,而不尝试锁定它。如果当前线程不拥有m,则行为未定义


但是,
pop
调用
data.empty
,这是私有成员的方法,而不是
threadsafe\u堆栈的成员函数
empty
。代码中没有问题。

不是100%确定您的意思,我猜您的意思是在同一线程中依次调用
pop
empty
?喜欢

while(!x.empty()) x.pop();
std::锁紧装置
跟随RAII。这意味着构造函数

std::lock_guard<std::mutex> lock(m);
std::锁和防护锁(m);
将获取/锁定互斥锁,析构函数(当
lock
超出范围时)将再次释放/解锁互斥锁。因此,它在下一次函数调用时被解锁

pop
内部,仅调用
data.empty()
,它不受互斥锁的保护。在
pop
内部调用
this->empty()
确实会导致未定义的行为

当一个在进入pop()时获得锁的线程调用同样受互斥锁保护的empty()时,这段代码如何不陷入死锁

因为您不是在调用
threadsafe_stack
empty
成员函数,而是在调用类
std::stack
的empty()。如果代码为:

void pop(T& value) 
{
    std::lock_guard<std::mutex> lock(m);
    if(empty()) // instead of data.empty()
        throw empty_stack();
    value = std::move(data.top());
    data.pop();
}
void pop(T&value)
{
标准:锁和防护锁(m);
if(empty())//而不是data.empty()
抛出空的_堆栈();
value=std::move(data.top());
data.pop();
}
那么,它将是:

如果锁由已经拥有互斥锁的线程调用,则行为未定义:例如,程序可能会死锁。鼓励能够检测到无效使用的实现抛出std::system_错误,错误条件为资源将发生死锁而不是死锁

了解和互斥