47

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);
    }
}
4

1 に答える 1

59

Microsoft が Windows API の実装を変更したため、Sleep(1)代わりにを使用する必要がなくなりました。Sleep(0)Sleep()

Sleep() の MSDN ドキュメントから、これは Sleep(0) で今起こっていることです:

値が 0 の場合、スレッドは残りのタイム スライスを実行準備ができている他のスレッドに放棄します。実行できるスレッドが他にない場合、関数はすぐに戻り、スレッドは実行を続けます。

これは、Windows XP で発生していたことです。

値が 0 の場合、スレッドは残りのタイム スライスを、実行の準備ができている同等の優先順位の他のスレッドに放棄します。実行する準備ができている同じ優先度のスレッドが他にない場合、関数はすぐに戻り、スレッドは実行を続けます。この動作は、Windows Server 2003 以降で変更されました。

「他のスレッド」と「同じ優先度の他のスレッド」の違いに注意してください。

Joe Duffy が Sleep(0) ではなく Sleep(1) を使用することを提案する唯一の理由は、Sleep() の値が最も短いため、同じ優先度の実行準備ができているスレッドが他にない場合に Sleep() がすぐに戻るのを防ぐためです。 、Windows XP で実行している場合。

Windows Server 2003 以降の OS バージョンでは、Sleep() の動作が変更されているため、これについて心配する必要はありません。

Joe のブログのこの部分に注目してください。

そこには明示的な Sleep がありますが、それを発行しても優先順位が低いため、プロデューサーをスケジュールすることはできません。

XP では、メイン スレッド (優先度の高いスレッド) が Sleep(0) を実行した場合でも、優先度の低いスレッドが不足していました。XP 以降では、Sleep(0) により優先度の低いスレッドの実行が許可されるため、これは発生しなくなります。

于 2013-05-16T10:09:23.640 に答える