4

プログラムでデッドロックの問題が発生しています。だから私はロックについて読んでいますが、問題はほとんどの情報が一貫していないか、プラットフォームが定義されていないことです. 再帰ロック (Mutex) と非再帰ロック (Mutex)で、最も受け入れられている答えは次のとおりです。

再帰的ミューテックスには所有権があるため、ミューテックスを取得するスレッドは、ミューテックスを解放するスレッドと同じでなければなりません。非再帰的ミューテックスの場合、所有権の感覚はなく、どのスレッドが最初にミューテックスを取得したかに関係なく、通常、どのスレッドもミューテックスを解放できます。多くの場合、このタイプの「ミューテックス」は実際にはセマフォ アクションに近く、必ずしもミューテックスを除外デバイスとして使用するわけではなく、2 つ以上のスレッド間の同期またはシグナリング デバイスとして使用します。

解説では、人々はそれは正しくないと言い、それについての言及はありません. そう...

1) スレッド A で非再帰的ミューテックスをロックすると、スレッド B はロックを取得せずにロックを解除できますか?

2) スレッド A によって非再帰的ミューテックスでロックが取得され、スレッド B がロックを取得するために呼び出した場合、スレッド B はロックが解放されるまで待機してロックを取得しますか、それとも例外をスローしますか? 再帰的ミューテックスのこの場合はどうですか? (適切な結論を下すことができなかった他の質問でも議論されています)

3) 再帰ロックを使用する場合、プロセスの終了時に、すべての再帰ロックを解放する必要がありますか? (プロセスが終了する場所によっては発生しません)

4) 再帰的ロックと非再帰的ロックを慎重に組み合わせて使用​​する場合、どのような問題に注目していますか?

PS: Windows プラットフォームとstd::thread.

4

4 に答える 4

8

Reentrant Mutexesに関する wiki を読むと、非常に役立つと思います。その他のスレッドのコメントに同意します。受け入れられた答えは間違っているか、少なくともその要点を非常に不十分に説明しています。

すべてのミューテックスには所有権の概念があります。それがSemaphoreとの違いです。ミューテックスをロックするスレッドは、常にそれをロック解除する必要があるスレッドです。これが、ミューテックスがデッドロックを引き起こす可能性がある理由の一部ですが、ミューテックスが意図した目的 (特定のコード ブロックへのアクセスを相互に排除する) のために機能する理由でもあります。

では、Recursive/Reenrant と通常の Mutex の違いは何でしょうか? 再帰的ミューテックスは、同じスレッドによって複数回ロックできます。ウィキを引用するには:

再帰ロック (再帰スレッドミューテックスとも呼ばれます) は、スレッドが保持している同じロックを再帰的に取得できるようにするロックです。この動作は通常のロックとは異なることに注意してください。通常、すでに通常のロックを保持しているスレッドが同じロックを再度取得しようとすると、デッドロックが発生します。

これが、2 つのミューテックス タイプの違いのすべてです。基本的に、再帰メソッド内にミューテックス ロックを配置し、ミューテックスが解放される前にメソッドが再帰する場合は、再帰ミューテックスが必要です。そうしないと、最初の再帰の後、ロックを 2 回目に取得できないため、即座にデッドロックが発生します。

実際、これが再帰ミューテックスを使用する唯一の理由です。同じスレッドが同じロックを解放せずに取得しようとする他のほとんどの状況は、再帰ミューテックスを必要とせずにロックを適切に取得/解放するようにリファクタリングできる可能性があります。そうすることで、はるかに安全になります。再帰関数は自然にバブルアウトし、RAII を想定して再帰ミューテックスのすべてのロックを解放しますが、他の状況では、ミューテックスを十分に解放できず、デッドロックが発生する可能性があります。

したがって、特定の質問に答えるには:

  1. いいえ、ミューテックス システムで特に許可されていない限り
  2. はい、どちらの場合も一般的ですが、これはブロック/スローに関してミューテックスの実装に固有のものです。私がこれまでに使用したほとんどすべてのシステムはブロックするだけです (そのため、同じスレッドが解放されずに 2 回ロックすると、非再帰的ミューテックスがデッドロックします)
  3. はい、通常は、適切な RAII を想定して解放され、プロセスが正常に終了します。ロックを保持している間に非正常に終了するプロセスは、ちょっと面倒なことになる可能性があります。
  4. 上記の説明を参照してください。具体的には、wiki から次のことに注意を向けてください。

再帰ロックは、取得された回数が所有者スレッドによって解放された回数と一致する場合にのみ、解放されたと言われることに注意してください。

于 2014-10-30T14:44:28.933 に答える
1

あなたはPOSIXミューテックスの議論を参照していますが、WindowsはとにかくPOSIXをサポートしておらず、詳細が異なる可能性のあるC++標準スレッドプリミティブを使用しています。

したがって、最初に標準ライブラリのドキュメントを確認することをお勧めします。たとえば、c++ 標準のunlock明示的な状態は次のとおりです。

Requires: 呼び出しスレッドはミューテックスを所有する必要があります。

于 2014-10-30T15:02:28.803 に答える
1

以下は、Linux pthread_mutex_lock man ページからのものです。

タイプ pthread_mutex_t の変数は、定数PTHREAD_MUTEX_INITIALIZER (高速ミューテックスの場合)、THREAD_RECURSIVE_MUTEX_INITIALIZER_NP (再帰ミューテックスの場合)、および PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP (エラー チェック ミューテックスの場合)を使用して、静的に初期化することもできます。

再帰error checking'' and的なミューテックスでは、pthread_mutex_unlock は、ミューテックスが開始時にロックされていること、および現在 pthread_mutex_unlock を呼び出している同じスレッドによってロックされていることを実行時に実際にチェックします。これらの条件が満たされない場合、エラー コードが返され、mutex は変更されません。 「高速」なミューテックスはそのようなチェックを行わないため、ロックされたミューテックスがその所有者以外のスレッドによってロック解除される可能性があります。これは移植性のない動作であり、依存してはなりません。

「ロックされたミューテックスは、非再帰的なミューテックスの種類を持つ所有者以外のスレッドによってロック解除される可能性がある」ようです

于 2016-11-30T17:50:41.757 に答える
0

実際、これらのケースをテストするには、簡単なプログラムを作成する必要があります。

  1. ミューテックスを適切に使用していると仮定すると、別のスレッドがミューテックスのロックを解除することはありません。どのスレッドでもミューテックスのロックを解除できる可能性があります。(編集:別のスレッドでミューテックスのロックを解除しようとしたことはありません。それは目的を無効にします)これは競合状態を引き起こします。

  2. 次のコードを検討してください。

    void criticalSection(){
        pthread_mutex_lock(&mutex)
        //dostuff
        pthread_mutex_unlock(&mutex)
    }
    

    スレッド A とスレッド B の 2 つのスレッドがあり、スレッド A が最初に関数に入ると、ロックを取得して何かを実行します。スレッド A がまだ関数内にあるときにスレッド B が入ると、スレッドはロックされます。スレッド A の実行時

      pthread_mutex_unlock(&mutex)
    

    スレッド B は「起動」され、処理を開始します。

  3. やりたいことは何でもできると思いますが、再帰ロックがある場合は、スレッドがまだ何かを実行中であり、おそらくそれが終了するのを待ちたいと思うでしょう。

  4. 競合状態のないマルチスレッド アプリケーションを見ていると思います。:-)

于 2014-10-30T14:46:55.967 に答える