Mutual Exclusion (相互排除) (ミューテックスの、作成、ロック/ロック解除、破棄)のミューテックスを処理する、組み込み手続き。
序文:
相互排除は、共有リソースへのアクセスを、直列にする方法です。
プログラマーが、スレッドが、別のスレッドによって既にアクセスされている、共有リソースにアクセスすることを望まない場合、ミューテックスを使うことができます。
論理的には、mutex は、キーが1つだけの鍵です:
- スレッドが、共有リソースにアクセスする場合、スレッドは、最初に鍵を取得する必要があります。
- スレッドが、いったん鍵を取得すると、他のスレッドは待機する必要があるため、他のスレッドが共有リソースにアクセスすることを心配せずに、共有リソースで必要な処理を実行できます。
- スレッドが、共有リソースの使用を終了すると、ミューテックスの鍵が解除され、他のスレッドが、共有リソースにアクセスできるようになります。
ミューテックスは、次の3つのことを保証する鍵です:
- 不可分性 - ミューテックスの鍵は不可分操作です。つまり、オペレーティング・システム(またはスレッド・ライブラリ)は、ミューテックスを施錠した場合、他のスレッドがこのミューテックスを同時に施錠できないことを保証します。
- 特異性 - スレッドがミューテックスを施錠できた場合、元のスレッドが開錠するまで、他のスレッドが、スレッドを施錠できないことが保証されます。
- 非ビジー待機 - スレッドが、2番目のスレッドによって施錠されたスレッドを施錠しようとすると、最初のスレッドは、2番目のスレッドによって開錠されるまで中断されます(CPUリソースを消費しません)。
開錠されると、最初のスレッドが目覚めて実行を継続します。この結果、ミューテックスはまた施錠されます。
これは、共有リソースへのアクセスを、直列化するプロトコルです。
このようなプロトコルは、保護されているリソース(暗黙のメイン・スレッドを含む)に触れる可能性のある、すべてのスレッドにわたって、mutex が保護しているリソースに、適用する必要があることに注意してください。
Mutex 機能は、切り離されたスレッドでも、完全に使用できます(そのハンドラーのみが、その識別子によってアクセスできなくなります)。
ミューテックスの 作成 / 破壊
MutexCreate は、ミューテックスを作成し、ミューテックスを破棄するときに参照されるハンドル識別子を返します。
MutexCreate で作成された mutex は、不要になったとき、または
MutexDestroy でプログラムが終了する前に、破棄する必要があります。
作成
- 構文:
- 用法:
- 戻り値:
作成されたミューテックスの
any ptr ハンドル
(mutexid)、または、失敗した場合は、null ポインター (
0) 。
破壊
説明
MutexCreate の呼び出しは、MutexCreate を使うスレッドを作成する前(および作成するスレッドで使うる前)に実行する必要があります。
MutexDestroy の呼び出しは、mutex を使うスレッドが使われなくなった後(および、mutex を破壊するスレッドで最後に使われた後)に実行する必要があります。
ミューテックスの施錠 / 開錠
MutexLock/
MutexUnlock は、作成時に取得するハンドル識別子を参照して、ミューテックスを施錠/開錠できます。
Lock
Unlock
説明
ミューテックスの施錠と開錠呼び出しの間のコードは、危険領域(critical section)と呼ばれます。
危険領域で費やされる時間を最小限に抑えると、他のスレッドが鍵を取得するために待つ時間を短縮できる可能性があるので、同時実行性が向上します。
したがって、できるだけ、スレッド・プログラマが、危険領域を最小化することが重要です。
擬似コードセクション
上記のすべての適切なルールを適用することにより:
' Principle of mutual exclusion between 2 threads
' (connecting lines join the sender(s) and receiver(s) impacted by each action occurring during the sequence)
'
' Thread Other Thread
' MUTEXLOCK(mutexID) <----------------. .---> MUTEXLOCK(mutexID)
' Do_something_with_exclusion .--- | ---' Do_something_with_exclusion
' MUTEXUNLOCK(mutexID) ----------' '--------- MUTEXUNLOCK(mutexID)
例
先のページ (
Threads) の最初の例は、各スレッドが単一の文字("M" か "C")を表示するのではなく、3文字(メインスレッドから "[M]" 、子スレッドの "(C)" )のシーケンスを表示するように変更されています。
各スレッドループのテンポは、スレッド間の表示を交互配置するために、3つの塊に分割されています。
- これをそのまま使う例:
Declare Sub thread (ByVal userdata As Any Ptr)
Dim As Any Ptr threadID '' declaration of an 'Any Ptr' thread-ID of the child thread
Print """[M]"": from 'Main' thread"
Print """(C)"": from 'Child' thread"
Print
threadID = ThreadCreate(@thread) '' creation of the child thread from the main thread
For I As Integer = 1 To 10 '' 'For' loop of the main thread
Print "[";
Sleep 50, 1
Print "M";
Sleep 50, 1
Print "]";
Sleep 50, 1
Next I
ThreadWait(threadID) '' waiting for the child thread termination
Print
Print "'Child' thread finished"
Sleep
Sub thread (ByVal userdata As Any Ptr) '' sub executed by the child thread
For I As Integer = 1 To 10 '' 'For' loop of the child thread
Print "(";
Sleep 50, 1
Print "C";
Sleep 50, 1
Print ")";
Sleep 250, 1
Next I
End Sub
出力例:
"[M]": from 'Main' thread
"(C)": from 'Child' thread
[(CM])[M][(MC])[M][(MC])[M][(MC])[M][M(]C)[M](C)(C)(C)(C)(C)
'Child' thread finished
画面は、各スレッドから出力される(3文字の)シーケンスの交ざりを強調表示します。
各スレッドで、3文字のシーケンスを表示するコード・セクションが、他のスレッドの表示によって中断されることはありません。
したがって、これらの2つのコード・セクションは、ブロック
[Mutexlock ... Mutexunlock] によって保護される危険領域と見なす必要があります。
- mutexで相互排除を使う:
' Principle of mutual exclusion
' Main thread XOR Child thread
' ..... .....
' MUTEXLOCK(mutID) MUTEXLOCK(mutID)
' Do_something_with_exclusion Do_something_with_exclusion
' MUTEXUNLOCK(mutID) MUTEXUNLOCK(mutID)
' ..... .....
Declare Sub thread (ByVal userdata As Any Ptr)
Dim As Any Ptr threadID '' declaration of an 'Any Ptr' thread-ID of the child thread
Dim Shared As Any Ptr mutID '' declaration of a global 'Any Ptr' mutex-ID
mutID = MutexCreate '' creation of the mutex
Print """[M]"": from 'Main' thread"
Print """(C)"": from 'Child' thread"
Print
threadID = ThreadCreate(@thread) '' creation of the child thread from the main thread
For I As Integer = 1 To 10 '' 'For' loop of the main thread
MutexLock(mutID) '' set mutex locked at the beginning of the exclusive section
Print "[";
Sleep 50, 1
Print "M";
Sleep 50, 1
Print "]";
MutexUnlock(mutID) '' set mutex unlocked at the end of the exclusive section
Sleep 50, 1
Next I
ThreadWait(threadID) '' waiting for the child thread termination
Print
Print "'Child' thread finished"
MutexDestroy(mutID) '' destruction of the mutex
Sleep
Sub thread (ByVal userdata As Any Ptr) '' sub executed by the child thread
For I As Integer = 1 To 10 '' 'For' loop of the child thread
MutexLock(mutID) '' set mutex locked at the beginning of the exclusive section
Print "(";
Sleep 50, 1
Print "C";
Sleep 50, 1
Print ")";
MutexUnlock(mutID) '' set mutex unlocked at the end of the exclusive section
Sleep 250, 1
Next I
End Sub
出力例:
"[M]": from 'Main' thread
"(C)": from 'Child' thread
[M](C)[M][M](C)[M][M](C)[M][M](C)[M][M](C)[M](C)(C)(C)(C)(C)
'Child' thread finished
このため、各 3文字シーケンスと比較して、表示が一貫したものになります。
参照