web-dev-qa-db-ja.com

ミューテックスはどのように実装されますか?

特定のアプリケーションに対して、いくつかの実装は他のものより優れていますか?自分でロールアウトして獲得できるものはありますか?

53
static_rtti

Wikipediaの Test-and-set 機械命令の説明を確認してください。これは、機械レベルで原子操作がどのように達成されるかを暗示しています。ほとんどの言語レベルのミューテックス実装は、テストと設定などのマシンレベルのサポートに依存していると想像できます。

29
Adamski

Adamskiのtest-and-set提案、「高速ユーザー空間ミューテックス」または futexes の概念も参照する必要があります。

フューテックスには、uncontendedミューテックスをロックまたはロック解除する一般的な場合にカーネルシステムコールを必要としないという望ましい特性があります。これらの場合、ユーザーモードコードはアトミック 比較とスワップ(CAS) 操作を使用して、ミューテックスをロックまたはロック解除します。

CASが失敗すると、mutexが競合し、カーネルシステムコール-sys_futex Linuxの場合-mutexを待機する(ロックの場合)か、他のスレッドをウェイクアップする(ロック解除の場合)ために使用する必要があります。

これを自分で実装することに真剣に取り組んでいる場合は、Ulrich Drepperの paper も読んでください。

22
David Joyner

mutex は、オペレーティングシステムのカーネルで実行し、周囲のコードの量をできる限り短くすることが好ましいため、別のプロセスへのタスク切り替え中の切断を回避できます。したがって、正確な実装は少し秘密です。しかし、それは複雑ではありません。これは基本的に、取得および設定するブールフィールドを持つオブジェクトです。

  • カウンタを使用すると、カウンタがセマフォになる可能性があります。
  • ミューテックスは、クリティカルセクションの開始点であり、内部でミューテックスを使用して、コードのセクションに入ることができるかどうかを確認します。ミューテックスが空いている場合、ミューテックスを設定し、コードを実行します。完了時にのみミューテックスを解放します。クリティカルセクションは、ミューテックスがロックされていることに気付いた場合、ミューテックスが解放されるのを待つことができます。

基本的なミューテックスロジックの周りには、オブジェクトにラップするラッパーがあります。その後、カーネルの外部で使用できるようにするラッパーオブジェクトが増えます。そして、.NETで使用できるようにする別のラッパー。そして、何人かのプログラマーは、論理的なニーズに合わせて、これに関する独自のラッパーコードを作成します。ラッパーの周りのラッパーは、本当にそれらを暗い領域にします。

さて、mutexの内部に関するこの基本的な知識があれば、カーネルとその下のハードウェアに依存する1つの実装を使用することを望みます。これらが最も信頼性が高いでしょう。 (ハードウェアがこれらをサポートしている場合。)使用しているミューテックスがこのカーネル/ハードウェアレベルで動作しない場合、信頼性はありますが、代替手段がない限り、使用しないことをお勧めします。

私の知る限り、Windows、Linux、および.NETはすべて、カーネル/ハードウェアレベルでミューテックスを使用します。

私がリンクしたウィキペディアのページでは、内部ロジックと可能な実装について詳しく説明しています。ミューテックスはハードウェアによって制御され、ミューテックスの取得/設定全体が indivisible step であることが望ましい。 (システムがタスクを途中で切り替えないようにするためだけに。)

9
Wim ten Brink

Interlocked.CompareExchange は、スピンロックを実装するのに十分です。しかし、正しいことをするのはかなり難しいです。関連する微妙な例については、 Joe Duffyのブログ を参照してください。

2
Joren

アトミックにロックを示すためのアセンブリの一部:

; BL is the mutex id
; shared_val, a memory address

CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry

.OutLoop1:

; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed

.OutLoop2: ; Lock Acquired
1