1

「C++ Concurrency In Action」という本を読んでいて、リスト 6.1 で使用されているミューテックスについて質問があります。コード スニペットは次のとおりです。

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ミューテックスをロックしてから、空のミューテックスを呼び出します。ただし、ミューテックスは recursive_mutex ではなく、コードは適切に機能します。std::mutexしたがって、との実際の違いは何なのか疑問std::recursive_mutexです。

4

2 に答える 2

4

data.empty()データメンバーからの関数のように見える呼び出しです。emptyあなたが示す機能と同じではありません。

もしそうなら、これは再帰呼び出しになります

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

そして何も機能しません。

于 2015-10-13T09:16:32.180 に答える
3

まあ、recursive_mutex... 再帰関数のためです!

一部のオペレーティング システムでは、同じミューテックスを 2 回ロックすると、システム エラーが発生する可能性があります (この場合、ロックが完全に解放され、アプリケーションがクラッシュし、実際にはあらゆる種類の奇妙で未定義の動作が発生する可能性があります)。

これを見てください(ばかげた例)

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

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

}

この関数は再帰的にインクリメントxし、共有にプッシュしqueueます。上で説明したように、同じロックが同じスレッドによって 2 回ロックされることはありませんが、共有キューが複数のスレッドによって変更されていないことを確認する必要があります。

簡単な解決策の 1 つは、再帰関数の外側に位置指定を移動することですが、それができない場合はどうなるでしょうか。呼び出された関数が共有リソースをロックできる唯一の関数である場合はどうなりますか?

たとえば、呼び出し関数は次のようになります。

switch(option){

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

}

もちろん、3 つすべて (shred_Array、shared_map、shared_queue) をロックするわけではなく、そのうちの 1 つだけが変更されます。

解決策は使用すること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);

}

同じスレッドがミューテックスを再帰的にロックする必要がない場合はstd::mutex、例のように regular を使用する必要があります。

PS。あなたのスニペットでemptyは、と同じではありませんT::empty。呼び出しは 再帰的に呼び出しdata.empty()ません。empty

于 2015-10-13T09:16:25.547 に答える