195

POSIX では、mutex を再帰的にすることができます。これは、同じスレッドが同じミューテックスを 2 回ロックでき、デッドロックしないことを意味します。もちろん、ロックを 2 回解除する必要もあります。そうしないと、他のスレッドがミューテックスを取得できません。pthread をサポートするすべてのシステムが再帰的ミューテックスもサポートしているわけではありませんが、POSIX に準拠したい場合は、 .

他の API (より高レベルの API) も通常、ロックと呼ばれることが多いミューテックスを提供します。一部のシステム/言語 (Cocoa Objective-C など) は、再帰的ミューテックスと非再帰的ミューテックスの両方を提供します。一部の言語では、どちらか一方しか提供されません。たとえば、Java のミューテックスは常に再帰的です (同じスレッドが同じオブジェクトに対して 2 回「同期」する場合があります)。それらが提供する他のスレッド機能によっては、再帰的ミューテックスがなくても問題ないかもしれません。なぜなら、再帰的ミューテックスは自分で簡単に作成できるからです (より単純なミューテックス/条件操作に基づいて、再帰的ミューテックスを自分で実装しました)。

私がよく理解していないこと: 非再帰的ミューテックスは何に適していますか? 同じミューテックスを 2 回ロックすると、スレッドのデッドロックが必要になるのはなぜですか? それを回避できる高水準言語でさえ (たとえば、これがデッドロックするかどうかをテストし、デッドロックする場合は例外をスローする)、通常はそれを行いません。代わりに、スレッドをデッドロックさせます。

これは、誤って 2 回ロックして 1 回だけロックを解除した場合のみであり、再帰的ミューテックスの場合、問題を見つけるのが難しいため、代わりにすぐにデッドロックして、間違ったロックが表示される場所を確認しますか? しかし、ロックを解除するときにロック カウンターを返すことで同じことを行うことはできませんでした。最後のロックを解放し、カウンターがゼロではないことが確実な状況では、例外をスローしたり、問題をログに記録したりできませんか? または、私が見落としている非再帰的ミューテックスの他のより便利なユースケースはありますか? それとも、非再帰的ミューテックスは再帰的ミューテックスよりもわずかに高速になる可能性があるため、単なるパフォーマンスでしょうか? ただし、これをテストしたところ、違いはそれほど大きくありません。

4

8 に答える 8

162

再帰的ミューテックスと非再帰的ミューテックスの違いは、所有権に関係しています。再帰的ミューテックスの場合、カーネルは、再帰と代わりにブロックすべき別のスレッドとの違いを検出できるように、最初にミューテックスを実際に取得したスレッドを追跡する必要があります。別の回答が指摘したように、このコンテキストを保存するためのメモリと、それを維持するために必要なサイクルの両方に関して、これの追加のオーバーヘッドの問題があります。

ただし、ここでも他の考慮事項があります。

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

ミューテックスの所有権に付随するもう 1 つのプロパティは、優先順位の継承をサポートする機能です。カーネルはミューテックスを所有するスレッドとすべてのブロッカーの ID を追跡できるため、優先スレッド システムでは、ミューテックスを現在所有しているスレッドの優先度を、最も優先度の高いスレッドの優先度にエスカレートすることが可能になります。現在ミューテックスでブロックされています。この継承により、このような場合に発生する可能性のある優先順位の逆転の問題が回避されます。(すべてのシステムがそのようなミューテックスで優先順位の継承をサポートしているわけではありませんが、所有権の概念によって可能になる別の機能であることに注意してください)。

従来の VxWorks RTOS カーネルを参照すると、次の 3 つのメカニズムが定義されています。

  • ミューテックス- 再帰をサポートし、オプションで優先順位の継承をサポートします。このメカニズムは、データの重要なセクションを一貫した方法で保護するために一般的に使用されます。
  • バイナリ セマフォ- 再帰なし、継承なし、単純な除外、テイカーとギバーが同じスレッドである必要はなく、ブロードキャスト リリースが利用可能。このメカニズムは、重要なセクションを保護するために使用できますが、スレッド間の一貫したシグナリングまたは同期にも特に役立ちます。
  • セマフォのカウント- 再帰や継承はなく、必要な初期カウントから一貫したリソース カウンターとして機能し、スレッドはリソースに対するネット カウントがゼロの場合にのみブロックします。

繰り返しますが、これはプラットフォームによって多少異なります。特に、これらのことを何と呼んでいるかは異なりますが、これは、概念とさまざまなメカニズムを代表するものでなければなりません。

于 2008-10-10T01:09:43.910 に答える
131

答えは効率ではありません。非再入可能ミューテックスは、より良いコードにつながります。

例: A::foo() はロックを取得します。次に、B::bar() を呼び出します。あなたがそれを書いたとき、これはうまくいきました。しかし、しばらくして誰かが B::bar() を変更して A::baz() を呼び出し、これもロックを取得します。

再帰的なミューテックスがない場合、これはデッドロックになります。持っていれば動きますが、壊れる可能性があります。A::foo() は、bar() を呼び出す前にオブジェクトを一貫性のない状態のままにしている可能性があります。これは、baz() がミューテックスも取得するために実行できないという前提に基づいています。しかし、おそらく実行すべきではありません。A::foo() を書いた人は、誰も同時に A::baz() を呼び出すことができないと想定していました - それが両方のメソッドがロックを取得した理由です。

ミューテックスを使用するための正しいメンタル モデル: ミューテックスは不変条件を保護します。ミューテックスが保持されると、不変条件が変更される可能性がありますが、ミューテックスを解放する前に、不変条件が再確立されます。再入可能ロックは危険です。2 回目にロックを取得したときに、不変式が真であるかどうかを確認できないからです。

再入可能ロックに満足している場合、それは、このような問題を以前にデバッグする必要がなかったからです。ところで、最近の Java には、java.util.concurrent.locks に再入不可のロックがあります。

于 2008-11-16T07:44:44.377 に答える
96

Dave Butenhof自身が書いたように

「再帰的ミューテックスの大きな問題の中で最大のものは、ロック スキームとスコープを完全に見失うことを助長することです。これは致命的です。悪です。それは「スレッド イーター」です。ロックを保持する時間は可能な限り最短です。ピリオド. 常に. ロックが保持されているかどうかわからない、または呼び出し先がミューテックスを必要としているかどうかわからないという理由だけで、ロックが保持された状態で何かを呼び出している場合は、保持時間が長すぎます.アプリケーションにショットガンを向けて、引き金を引きます。スレッドを使用して同時実行性を確保し始めたと思われますが、同時実行性を妨げただけです。」

于 2009-08-07T14:20:38.433 に答える
12

ミューテックスを使用するための正しいメンタル モデル: ミューテックスは不変条件を保護します。

これがミューテックスを使用するための本当に正しいメンタル モデルであると確信できるのはなぜですか? 正しいモデルはデータを保護していますが、不変条件は保護していないと思います。

不変条件を保護するという問題は、シングルスレッド アプリケーションでも発生し、マルチスレッドやミューテックスと共通するものは何もありません。

さらに、不変条件を保護する必要がある場合でも、再帰的でないバイナリ セマフォを使用できます。

于 2008-12-16T11:41:11.630 に答える
6

再帰ミューテックスの唯一の適切な使用例は、オブジェクトに複数のメソッドが含まれている場合です。いずれかのメソッドがオブジェクトのコンテンツを変更するため、状態が再び整合する前にオブジェクトをロックする必要がある場合。

メソッドが他のメソッドを使用する (つまり、addNewArray() が addNewPoint() を呼び出し、recheckBounds() で終了する) が、それらの関数のいずれか自体がミューテックスをロックする必要がある場合、再帰ミューテックスは双方にメリットがあります。

それ以外の場合 (悪いコーディングだけを解決し、別のオブジェクトでも使用する) は明らかに間違っています!

于 2015-11-20T14:30:40.813 に答える
6

再帰的ミューテックスが有用である主な理由の 1 つは、同じスレッドによってメソッドに複数回アクセスする場合です。たとえば、ミューテックス ロックが銀行 A/c の引き出しを保護している場合、その引き出しにも手数料がかかる場合、同じミューテックスを使用する必要があります。

于 2015-05-29T13:41:01.073 に答える