2016-11-15 16 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; 
} 
}; 

エラー:私のコメントを1として

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()メソッドでキューをロックし、空であれば要素があるまで待機します。追加します。ロック障壁の間に決して待ってはいけません。また、使用されているスコープにロックを作成して、スコープが例外の場合でもクリーンアップするようにするか、例外的にロックが解放されることもあります。 – Rob

+1

@Rob - 条件変数は、原子的に待機を開始し、/を保護するmutexをロック解除します。その部分はOKで、標準的な使い方です。 – BadZen

答えて

1

:unique_lockの、名前が示すように、のみ/ 1 /ロッキングスレッドによって使用することを意図しています。別のスレッドからロックするには、別のロックが必要です。これの成果 - 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... 
} 

... 

など。

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; 
} 

の理由は、非常によく:-)コメントで説明されています

0

は、クラス内のunique_lockを削除し、次のようにあなたのpushpop機能を変更することを検討してください。

のようなメンバー機能をconstに提供する場合は、mtxmutableに変更することもできます。またはコンストラクタをコピーします。