1. ホーム
  2. multithreading

[解決済み] 再帰的ロック (Mutex) vs 非再帰的ロック (Mutex)

2022-04-22 02:48:49

質問

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

他のAPI(より高度なAPI)も通常、ミューテックス(しばしばロックと呼ばれる)を提供します。Cocoa Objective-Cのようなシステム/言語では、再帰的なミューテックスと非再帰的なミューテックスの両方が提供されます。また、どちらか一方しか提供しない言語もあります。例えば、Javaでは、ミューテックスは常に再帰的です(同じスレッドが同じオブジェクトに対して2回"synchronize"することができます)。その言語が提供する他のスレッド機能によっては、再帰的なミューテックスを持たないことは問題ではないかもしれません。

よくわからないこと 非再帰型ミューテックスは何のためにあるのでしょうか?同じミューテックスを2回ロックすると、なぜスレッドがデッドロックするのでしょうか?それを避けることができる高レベルの言語(例えば、これがデッドロックになるかどうかをテストし、デッドロックになった場合は例外を投げる)であっても、通常はそれを行いません。代わりにスレッドをデッドロックさせるのです。

これは、誤って2回ロックして1回だけ解除するような場合だけで、再帰的なミューテックスの場合は問題を見つけるのが難しいので、代わりにすぐにデッドロックさせて、誤ったロックがどこに現れるかを確認するためでしょうか。しかし、ロック解除時にロックカウンターを返して、最後のロックを解放したことが確実でカウンターがゼロでない状況で、例外をスローするか、問題をログに残すことはできないのでしょうか?それとも、再帰的でないミューテックスには、もっと便利な使い道があるのでしょうか? あるいは、非再帰型ミューテックスは再帰型ミューテックスよりわずかに速いので、単に性能の問題なのでしょうか?しかし、実際にテストしてみると、その差はそれほど大きくはありません。

解決方法は?

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

しかし しかし、それ以外にも考慮すべき点があります。

再帰型ミューテックスには所有者意識があるため、ミューテックスを取得したスレッドは、ミューテックスを解放するスレッドと同じでなければなりません。非再帰型 Mutex の場合、所有者意識はなく、どのスレッドが最初に Mutex を取得しても、通常 Mutex を解放することができます。多くの場合、このタイプの "mutex"は、実際にはセマフォの動作に近く、必ずしも排除装置としてmutexを使用するのではなく、2つ以上のスレッド間の同期または信号伝達装置として使用されるものです。

また、ミューテックスに所有感を持たせることで得られる特性として、優先順位の継承をサポートできることが挙げられます。カーネルは、ミューテックスを所有するスレッドと、すべてのブロッカーの身元を追跡できるため、優先スレッドシステムでは、現在ミューテックスを所有しているスレッドの優先度を、現在ミューテックスでブロックしている最も高い優先度のスレッドの優先度にエスカレートすることが可能になる。この継承により、このようなケースで発生しうる優先度の逆転の問題を防ぐことができます。(すべてのシステムがこのようなミューテックスの優先順位継承をサポートしているわけではありませんが、これも所有権の概念によって可能になる機能です)。

古典的なVxWorks RTOSカーネルを参照すると、彼らは3つのメカニズムを定義しています。

  • ミュートス - は再帰性をサポートし、オプションで優先順位の継承も可能です。この機構は、データの重要な部分を首尾一貫して保護するためによく使われます。
  • バイナリセマフォ - 再帰なし、継承なし、単純排他、受け手と渡し手が同じスレッドである必要はない、ブロードキャストリリースが利用できる。この機構は、クリティカルセクションの保護に使用できますが、スレッド間のコヒーレントな信号や同期にも特に有用です。
  • カウントセマフォ - 再帰や継承を行わず、任意の初期カウントから一貫したリソースカウンタとして動作し、スレッドはリソースに対する正味カウントが0である場合にのみブロックされます。

繰り返しますが、これはプラットフォームによって多少異なります。特に、プラットフォームがこれらをどのように呼ぶかは異なりますが、これは概念と様々なメカニズムを代表するものであるはずです。