これはThread.MemoryBarrier()の正しい使用法ですか?
いいえ。ループの実行が開始される前に、1つのスレッドがフラグを設定するとします。フラグのキャッシュされた値を使用して、ループを1回実行することもできます。それは正しいですか?それは確かに私には間違っているようです。ループを最初に実行する前にフラグを設定すると、ループは1回ではなく、0回実行されると思います。
Thread.MemoryBarrier()を理解している限り、whileループ内でこの呼び出しを行うと、作業スレッドがキャッシュされたバージョンのshouldRunを取得できなくなり、無限ループが発生するのを効果的に防ぐことができます。Thread.MemoryBarrierについての私の理解は正しいですか?
メモリバリアは、プロセッサが読み取りと書き込みの並べ替えを行わないことを保証します。これにより、論理的にバリアの前にあるメモリアクセスが実際にバリアの後にあることが観察され、その逆も同様です。
ローロックコードを実行することにひどい思いをしているのであれば、明示的なメモリバリアを導入するのではなく、フィールドを揮発性にする傾向があります。「揮発性」はC#言語の機能です。危険でよく理解されていない機能ですが、言語の機能です。これは、問題のフィールドが複数のスレッドをロックせずに使用されることをコードのリーダーに明確に伝えます。
これは、スレッドによってshouldRunがfalseに設定されたときにループが停止することを保証するための合理的な方法ですか?
一部の人々はそれを合理的だと考えるでしょう。非常に正当な理由がなければ、自分のコードでこれを行うことはありません。
通常、ローロック手法はパフォーマンスの考慮事項によって正当化されます。そのような考慮事項は2つあります。
まず、競合するロックは潜在的に非常に遅いです。ロック内で実行されているコードがある限り、ブロックされます。競合が多すぎるためにパフォーマンスの問題が発生した場合は、最初に競合を排除して問題を解決しようとします。競合を排除できなかった場合にのみ、ローロック手法を採用します。
第二に、競合していないロックが遅すぎる可能性があります。ループで実行している「作業」にかかる時間がたとえば200ナノ秒未満の場合、競合のないロックをチェックするために必要な時間(約20 ns)は、作業に費やされる時間のかなりの部分です。その場合、ループごとにより多くの作業を行うことをお勧めします。制御フラグが設定されてから200ns以内にループが停止することが本当に必要ですか?
最も極端なパフォーマンスシナリオでのみ、競合のないロックをチェックするコストがプログラムで費やされる時間のかなりの部分であると想像します。
また、もちろん、200 ns程度ごとにメモリバリアを誘発している場合は、他の方法でパフォーマンスを低下させている可能性もあります。プロセッサは、これらの移動メモリアクセスを時間内に最適化することを望んでいます。あなたがそれらの最適化を絶えず放棄することを強制しているなら、あなたは潜在的な勝利を逃しています。