これはばかげた質問のように聞こえるかもしれませんが、マルチスレッド アプリでリソースをロックすると、そのリソースで発生する操作はアトミックに行われるのでしょうか?
IE: リソースがロックされている間に、プロセッサが中断されたり、コンテキストの切り替えが発生したりする可能性はありますか? そうである場合、そのプロセスを終了するために再びスケジュールされるまで、他の誰もこのリソースにアクセスできません。高価な操作のように聞こえます。
これはばかげた質問のように聞こえるかもしれませんが、マルチスレッド アプリでリソースをロックすると、そのリソースで発生する操作はアトミックに行われるのでしょうか?
IE: リソースがロックされている間に、プロセッサが中断されたり、コンテキストの切り替えが発生したりする可能性はありますか? そうである場合、そのプロセスを終了するために再びスケジュールされるまで、他の誰もこのリソースにアクセスできません。高価な操作のように聞こえます。
はい、プロセッサは間違いなく別のスレッドに切り替えることができます。実際、最近のほとんどのコンピューターでは、複数のスレッドが同時に実行されている可能性があります。ロックは、他のスレッドが同じロックを取得できないことを確認するだけなので、そのリソースに対する操作がそのリソースに関してアトミックであることを確認できます。他のリソースを使用するコードは、完全に独立して動作できます。
通常は、可能な限り短時間の操作でロックする必要があります。また、ロックの粒度を選択することもできます。たとえば、共有オブジェクトに 2 つの独立した変数がある場合、それらの変数へのアクセスを保護するために 2 つの個別のロックを使用できます。これにより、同時実行性が向上する可能性がありますが、同時にロックが増えると、複雑さが増し、デッドロックが発生する可能性が高くなります。並行性に関しては、常にバランスをとる行為があります。
その通りです。これが、短時間ロックすることが非常に重要な理由の 1 つです。ただし、ロックを保持しているスレッドがロックを解放するまで、ロックを待機している他のスレッドはスケジュールされないため、これは思ったほど悪くはありません。
はい、コンテキスト スイッチは間違いなく発生する可能性があります。これがまさに、共有リソースにアクセスするときに、別のスレッドからもロックすることが重要な理由です。スレッド A がロックされている場合、スレッド B はロックされたコードにアクセスできません。
たとえば、2 つのスレッドが次のコードを実行するとします。
1. lock(l);
2. -- change shared resource S here --
3. unlock(l);
ステップ 1 の後にコンテキストの切り替えが発生する可能性がありますが、その時点で他のスレッドはロックを保持できないため、共有リソースを変更できません。スレッドの 1 つで共有リソースへのアクセスがロックなしで行われると、悪いことが起こる可能性があります。
無駄遣いに関しては、そうです、もったいない方法です。これが、ロックを完全に回避しようとする方法がある理由です。これらの方法はロックフリーと呼ばれ、一部はCAS (Compare-And-Swap)などの強力なロック サービスに基づいています。
いいえ、それほど高価ではありません。通常、2つの可能性しかありません。
1)システムには、他に実行できることがあります。この場合、システムは、使用可能なすべてのコアで引き続き有用な作業を実行しています。
2)システムには他に何もする必要はありません。この場合、ロックを保持するスレッドがスケジュールされます。スケジュールされていないすぐに実行できるスレッドがある間、正常なシステムはコアを未使用のままにしません。
それで、それはどのように高価になることができますか?システムが他に何もすることがない場合、そのロックを取得する必要はなく(またはすべてのコアを占有するのに十分な他のものがない)、ロックを保持しているスレッドはすぐに実行できません。したがって、これは避けなければならないケースであり、コンテキストスイッチやプリエンプトの問題は問題ではありません(スレッドはすぐに実行できるため)。