ミューテックスは他の問題を解決するために使用できますが、それらが存在する主な理由は相互排除を提供し、それによって競合状態として知られているものを解決することです。2つ(またはそれ以上)のスレッドまたはプロセスが同じ変数に同時にアクセスしようとすると、競合状態になる可能性があります。次のコードを検討してください
//somewhere long ago, we have i declared as int
void my_concurrently_called_function()
{
i++;
}
この関数の内部はとてもシンプルに見えます。それはたった1つのステートメントです。ただし、同等の典型的な疑似アセンブリ言語は次のようになります。
load i from memory into a register
add 1 to i
store i back into memory
iでインクリメント操作を実行するには、同等のアセンブリ言語命令がすべて必要なので、iのインクリメントは非アトミック操作であると言います。アトミック操作は、命令の実行が開始されたら中断されないという保証でハードウェア上で完了することができる操作です。iの増分は、3つのアトミック命令のチェーンで構成されます。複数のスレッドが関数を呼び出している並行システムでは、スレッドが誤ったタイミングで読み取りまたは書き込みを行うと問題が発生します。2つのスレッドが同時に実行され、1つが次の関数をすぐに呼び出すとします。また、0に初期化したとしましょう。また、十分なレジスタがあり、2つのスレッドが完全に異なるレジスタを使用しているため、衝突は発生しないと仮定します。これらのイベントの実際のタイミングは次のとおりです。
thread 1 load 0 into register from memory corresponding to i //register is currently 0
thread 1 add 1 to a register //register is now 1, but not memory is 0
thread 2 load 0 into register from memory corresponding to i
thread 2 add 1 to a register //register is now 1, but not memory is 0
thread 1 write register to memory //memory is now 1
thread 2 write register to memory //memory is now 1
何が起こったかというと、2つのスレッドがiを同時にインクリメントしているため、関数が2回呼び出されますが、結果はその事実と一致しません。関数が一度だけ呼び出されたようです。これは、アトミック性がマシンレベルで「壊れている」ためです。つまり、スレッドが互いに割り込んだり、間違ったタイミングで連携したりする可能性があります。
これを解決するメカニズムが必要です。上記の手順にいくつかの順序を課す必要があります。一般的なメカニズムの1つは、1つを除くすべてのスレッドをブロックすることです。Pthread mutexはこのメカニズムを使用します。
(電話を使用して妻と話すことにより)同時に他のスレッドによる共有値を安全に変更できないコード行を実行する必要があるスレッドは、最初にミューテックスのロックを取得する必要があります。このように、共有データへのアクセスを必要とするスレッドは、ミューテックスロックを通過する必要があります。そうして初めて、スレッドはコードを実行できるようになります。このコードセクションは、クリティカルセクションと呼ばれます。
スレッドがクリティカルセクションを実行すると、別のスレッドがミューテックスのロックを取得できるように、ミューテックスのロックを解放する必要があります。
ミューテックスを持つという概念は、実際の物理オブジェクトへの排他的アクセスを求める人間を考えると少し奇妙に見えますが、プログラミングするときは意図的にする必要があります。並行スレッドとプロセスには、私たちが行うような社会的および文化的な育成がないため、データを適切に共有するように強制する必要があります。
技術的に言えば、mutexはどのように機能するのでしょうか。以前に述べたのと同じ競合状態に悩まされていませんか?pthread_mutex_lock()は、変数を単純にインクリメントするよりも少し複雑ではありませんか?
技術的に言えば、私たちを助けるためにいくつかのハードウェアサポートが必要です。ハードウェア設計者は、複数のことを行うがアトミックであることが保証されている機械命令を提供します。このような命令の典型的な例は、テストアンドセット(TAS)です。リソースのロックを取得しようとするとき、TASを使用してメモリ内の値が0かどうかを確認することがあります。0の場合、それはリソースが使用中で何もしない(またはより正確に)というシグナルになります。 、何らかのメカニズムで待機します。pthreadsミューテックスにより、オペレーティングシステムの特別なキューに入れられ、リソースが利用可能になったときに通知されます。Dumberシステムでは、タイトなスピンループを実行して、条件を繰り返しテストする必要がある場合があります) 。メモリ内の値が0でない場合、TASは他の命令を使用せずに場所を0以外に設定します。それ' 2つのアセンブリ命令を1つに組み合わせて原子性を与えるようなものです。したがって、値のテストと変更(変更が適切な場合)は、いったん開始すると中断できません。そのような命令の上にミューテックスを構築することができます。
注:一部のセクションは、以前の回答と同様に表示される場合があります。私は彼の編集への招待を受け入れました、彼はそれが元の方法を好んだので、私は彼の言葉遣いの少しが注入された私が持っていたものを保持しています。