Joe Duffy ( Concurrent Programming on Windowsの著者) は、このブログ記事で、Thread.Sleep(1) は Thread.Sleep(0) よりも優先されると書いています。なぜなら、Thread.Sleep(1) は、Thread と同じ優先度のスレッドだけでなく、同じ優先度のスレッドとそれよりも優先度の低いスレッドに対してもサスペンドするからです。 .スリープ(0).
MSDNの.NET バージョンによると、Thread.Sleep(0) は特別であり、このスレッドを一時停止し、待機中の他のスレッドを実行できるようにします。ただし、 Thread.Sleep(1) (すべての .NET バージョン) については何も述べていません。
では、Thread.Sleep(1) は実際に何か特別なことをしているのでしょうか?
バックグラウンド:
並行プログラミングの知識を一新しています。プリ/ポスト インクリメントとデクリメントが非アトミックであり、したがってスレッド セーフではないことを視覚的に示すために、いくつかの C# コードを作成しました。
何百ものスレッドを作成する必要がないように、共有変数をインクリメントした後に Thread.Sleep(0) を配置して、スケジューラに別のスレッドを強制的に実行させます。この定期的なスレッドの交換により、プリ/ポスト インクリメント/デクリメントの非アトミックな性質がより明確になります。
予想どおり、Thread.Sleep(0) は追加の遅延を引き起こさないようです。ただし、これを Thread.Sleep(1) に変更すると、通常のスリープ動作に戻ったように見えます (たとえば、おおよそ最低 1 ミリ秒の遅延が発生します)。
これは、Thread.Sleep(1) が優先される可能性がありますが、ループ内でそれを使用するコードは実行速度が大幅に低下することを意味します。
この SO の質問は、「Sleep(1) でこの興味深い動作を説明できる人はいますか?」というものです。関連性がありますが、C++ に焦点を当てており、Joe Duffy のブログ記事のガイダンスを繰り返しているだけです。
興味のある人のための私のコードは次のとおりです(LinqPadからコピーされたので、その周りにクラスを追加する必要があるかもしれません):
int x = 0;
void Main()
{
List<Thread> threadList=new List<Thread>();
Stopwatch sw=new Stopwatch();
for(int i=0; i<20; i++)
{
threadList.Add(new Thread(Go));
threadList[i].Priority=ThreadPriority.Lowest;
}
sw.Start();
foreach (Thread thread in threadList)
{
thread.Start();
}
foreach (Thread thread in threadList)
{
thread.Join();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Thread.Sleep(200);
Console.WriteLine(x);
}
void Go()
{
for(int i=0;i<10000;i++)
{
x++;
Thread.Sleep(0);
}
}