ミューテックスの背後にある考え方は、一度に1つのスレッドのみがメモリのセクションにアクセスできるようにすることです。 1つのスレッドがミューテックスをロックすると、他のロックの試行は最初のスレッドがロック解除されるまでブロックされます。しかし、これはどのように実装されていますか?自分自身をロックするには、ミューテックスがロックされていることを示すビットをどこかに設定する必要があります。しかし、2番目のミューテックスが同時に読み取りを行っている場合はどうなりますか?さらに悪いことに、両方が同時にミューテックスをロックした場合はどうなりますか?ミューテックスは、それが防ぐことを意図しているのと同じ問題に屈するでしょう。
ミューテックスは実際にどのように機能しますか?
低レベルのアトミック操作。これらは基本的にハードウェアに実装されたミューテックスですが、アトミックに実行できる操作はごくわずかです。
次の同等の擬似コードを検討してください。
mutex global_mutex;
void InterlockedAdd(int& dest, int value) {
scoped_lock lock(mutex);
dest += value;
}
int InterlockedRead(int& src) {
scoped_lock lock(mutex);
return src;
}
void InterlockedWrite(int& dest, int value) {
scoped_lock lock(mutex);
dest = value;
}
これらの関数はCPUによる命令として実装され、さまざまな程度でスレッド間の一貫性を保証します。正確なセマンティクスは、問題のCPUによって異なります。 x86は逐次一貫性を提供します。これは、操作が、ある順序で順番に発行されたかのように動作することを意味します。これは明らかに少しブロックすることを含みます。
アトミック操作はミューテックスの観点から実装できる、またはその逆であると正確に推測できます。ただし、通常、アトミックopsはハードウェアによって提供され、その後、オペレーティングシステムによってミューテックスやその他の同期プリミティブがそれらの上に実装されます。これは、完全なミューテックスを必要とせず、「ロックレス」と呼ばれるものを操作できるアルゴリズムがいくつかあるためです。つまり、スレッド間の一貫性のためにアトミック操作を使用するだけです。
過去に使用された単純な実装は、CPUレベルのアトミックな「ロックと交換」命令を使用することです。これは、特定の値を特定のメモリ位置の値とアトミックに交換する特別な命令です。
スレッドは、1の値をメモリ位置にスワップしようとすることで、このようなミューテックスを取得できます。値が0に戻った場合、スレッドはミューテックスを持っていると見なして続行します。それ以外の場合、返される値が1の場合、スレッドは一部のotherスレッドに現在ミューテックスがあることを認識します。その場合、再試行するまで待機します。
上記は、単純なシステムで発生する可能性のあることの非常に単純化された概要です。最近の実際のオペレーティングシステムははるかに複雑です。
これはミューテックスが機能するために必要なものの簡単な概要です、それは私の完全な記事の短縮形です ミューテックスはどのように機能しますか?
compare_and_swap
関数が必要です。これにより、スレッドは状態のチェックと変更の両方を同時に行うことができます。futex
です。これにより、スレッドがキューに入れられ、メモリ内の整数も監視されます。必要なのはそれを原子的に行うことです。これは、アトミックな比較交換命令などのハードウェアによって、またはシステムコールを介してオペレーティングシステムによって提供できます。 OSドメインに入ると、1つのスレッドだけがミューテックスをロックしようとしていることを確認するのはかなり簡単です。
実際には、両方のアプローチが組み合わされています。たとえば、Linuxのfutexを参照してください。