再帰的ミューテックスでは、デッドロックに陥ることなくミューテックスを複数回ロックでき、同じ回数ロックを解除する必要があることを理解しています。しかし、どのような特定の状況で、再帰的なミューテックスを使用する必要がありますか?設計/コードレベルの状況を探しています。
たとえば、再帰的に呼び出す関数があり、その関数への同期アクセスを取得する場合:
void foo() {
... mutex_acquire();
... foo();
... mutex_release();
}
再帰的なミューテックスがなければ、最初に「エントリポイント」関数を作成する必要があり、相互に再帰的な関数のセットがある場合、これは面倒になります。再帰的ミューテックスなし:
void foo_entry() {
mutex_acquire(); foo(); mutex_release(); }
void foo() { ... foo(); ... }
再帰的および非再帰的ミューテックスには、異なるユースケースがあります。ミューテックスタイプで他のミューテックスを簡単に置き換えることはできません。非再帰的なミューテックスはオーバーヘッドが少なく、再帰的なミューテックスは有用な、または必要なセマンティクスでさえあり、他の状況では危険な、または壊れたセマンティクスでさえあります。ほとんどの場合、誰かは再帰的ミューテックスを使用する戦略を、非再帰的ミューテックスの使用に基づいて、より安全で効率的な別の戦略に置き換えることができます。
再帰的なミューテックスを使用するコードの例をご覧になりたい場合は、Linux/Unix用の「Electric Fence」のソースをご覧ください。 ' Valgrind が登場する前に、「バウンドチェック」読み取り/書き込みオーバーランとアンダーランを見つけ、解放されたメモリを使用するための一般的なUnixツールの1つでした。
ソースと電気フェンスをコンパイルしてリンクし(オプション-g with gcc/g ++)、リンクオプション-lefenceでソフトウェアとリンクし、malloc/freeの呼び出しをステップ実行します。 http://elinux.org/Electric_Fence
今日、再帰的なmutexの必要性に遭遇しましたが、これはこれまでに投稿された回答の中でおそらく最も単純な例だと思います。これは、Process(...)とreset()の2つのAPI関数を公開するクラスです。
public void Process(...)
{
acquire_mutex(mMutex);
// Heavy processing
...
reset();
...
release_mutex(mMutex);
}
public void reset()
{
acquire_mutex(mMutex);
// Reset
...
release_mutex(mMutex);
}
両方の関数はクラスの内部を変更するため、同時に実行しないでください。したがって、ミューテックスを使用したいと考えました。問題は、Process()が内部でreset()を呼び出し、mmutexがすでに取得されているためデッドロックが発生することです。代わりに再帰ロックでロックすると、問題が修正されます。
スレッドが既に所有しているミューテックスを(もう一度)取得しようとしてブロックされた場合、それは確かに問題になります...
同じスレッドがミューテックスを複数回取得できないようにする理由はありますか?