2016-11-15 165 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成員函數;或複製構造函數。