2016-11-15 153 views
0

我写了一个线程安全队列,它给出了死锁错误。我无法找出原因。我修改了函数来使用本地锁,而不是成员变量锁。然后,它似乎运行良好。线程安全队列死锁

代码:

template <typename T> 
class MyQueue { 
queue<T> arr; 

mutex mtx; 
unique_lock<mutex> lck; 
condition_variable cv; 
public: 
MyQueue() { 
    lck = unique_lock<mutex>(mtx, defer_lock); 
} 

void push(int tmp) { 
    lck.lock(); 
    arr.push(tmp); 
    lck.unlock(); 
    cv.notify_one(); 
} 

int pop() { 
    T x; 
    lck.lock(); 
    while(arr.size() == 0) 
     cv.wait(lck); 
    x = arr.front(); 
    arr.pop(); 
    lck.unlock(); 
    return x; 
} 

int getCount() { 
    T x; 
    lck.lock(); 
    x = arr.size(); 
    lck.unlock(); 

    return x; 
} 
}; 

错误:

libc++abi.dylib: libc++abi.dylib: libc++abi.dylib: terminating with 
uncaught exception of type std::__1::system_error: unique_lock::lock: already locked: 
Resource deadlock avoidedterminating with uncaught exception of type std::__1::system_error: 
unique_lock::lock: already locked: Resource deadlock avoidedlibc++abi.dylib: 
terminating with uncaught exception of type std::__1::system_error: unique_lock::lock: already locked: Resource deadlock avoided 
+0

正如其名称所暗示的那样,'unique_lock'仅供/ one/locking线程使用。要从另一个线程锁定,您需要另一个锁。结果是 - 在每个函数中使'unique_lock'成为本地,而不是类成员。 – BadZen

+0

我看到一个大问题:你在你的pop()方法中锁定你的队列,如果它是空的,你等待/循环,直到它有一个元素。这不会发生,因为你有它锁定,所以push()不能锁定它加。永远不要在锁屏之间等待。你也应该在它使用的范围内创建锁,这样当范围存在时,即使在例外的情况下,它也会被清除,或者你最终可能得到一个在异常情况下也不会被释放的锁。 – Rob

+1

@Rob - 条件变量自动等待开始等待和/解锁保护条件的互斥/。这部分是好的,并且是标准用法。 – BadZen

回答

1

按我的意见:unique_lock,顾名思义,旨在用于只/一个/锁螺纹。要从另一个线程锁定,您需要另一个锁。这样做的结果 - 使unique_lock成为每个函数中的局部变量,而不是类成员。

template <typename T> 
class MyQueue { 
queue<T> arr; 

mutex mtx; 
condition_variable cv; 
public: 
MyQueue() { 
} 

void push(int tmp) { 
    unique_lock<mutex> lck(mtx); 
    arr.push(tmp); 
    cv.notify_one(); 
    lck.unlock(); // Not nec'y, but polite... 
} 

... 

等等。

0

考虑删除unique_lock内部类,并改变你的pushpop功能如下:

void push(int tmp) 
{ 
    std::lock_guard<std::mutex> lkg(mtx); // Here unique_lock not necessary. 
    arr.push(tmp); 
    cv.notify_one(); 
} 

int pop() 
{ 
    std::unique_lock<std::mutex> ulk(mtx); 
    cv.wait(ulk, [this]() { return arr.size() != 0; }); 

    auto x = arr.front(); 
    arr.pop(); 
    return x; 
} 

的原因是在评论非常好解释:-)。

您可能还需要你mtx改变mutable如果要提供像empty()const成员函数;或复制构造函数。