19

次のコードをデバッグモードで実行すると、正常に終了して終了します。ただし、次のコードをリリースモードで実行すると、無限ループに陥って終了しません。

static void Main(string[] args)
{
    bool stop = false;

    new Thread(() =>
    {
        Thread.Sleep(1000);
        stop = true;
        Console.WriteLine("Set \"stop\" to true.");

    }).Start();

    Console.WriteLine("Entering loop.");

    while (!stop)
    {
    }

    Console.WriteLine("Done.");
}

無限ループに陥る原因となっている最適化はどれですか?

4

4 に答える 4

18

stop私の推測では、メイン スレッドでの変数のプロセッサ キャッシュです。デバッグ モードでは、メモリ モデルはより厳密になります。これは、デバッガーがすべてのスレッドにわたって変数の状態を適切に表示できる必要があるためです。

フィールドを作成してvolatileとしてマークしてみてください:

volatile bool stop = false;

static void Main(string[] args)
{

    new Thread(() =>
    {
        Thread.Sleep(1000);
        stop = true;
        Console.WriteLine("Set \"stop\" to true.");

    }).Start();

    Console.WriteLine("Entering loop.");

    while (!stop)
    {
    }

    Console.WriteLine("Done.");
}
于 2012-05-25T04:21:20.520 に答える
11

stopスレッド セーフではないため、子スレッド内のメイン スレッド変数を更新します。それは常に予測不可能です。このような状況に対処するには、この記事をご覧ください。

volatile キーワードは、そのフィールドからの読み取りごとに取得フェンスを生成し、そのフィールドへの書き込みごとに解放フェンスを生成するようにコンパイラに指示します。取得フェンスは、他の読み取り/書き込みがフェンスの前に移動するのを防ぎます。release-fence は、他の読み取り/書き込みがフェンスの後に移動されるのを防ぎます。これらの「ハーフフェンス」は、ランタイムとハードウェアに最適化の余地を与えるため、フルフェンスよりも高速です。

于 2012-05-25T04:21:01.107 に答える
0

スレッド アンセーフ コードは予測できません。主な問題は、あるスレッド変数を別のスレッドから変更することです。変数をグローバルまたは揮発性にします。あなたは次のことでそれを行うことができます

static volatile bool stop = false;

static void Main(string[] args)
{    
    new Thread(() =>
    {
        Thread.Sleep(1000);
        stop = true;
        Console.WriteLine("Set \"stop\" to true.");

    }).Start();

    Console.WriteLine("Entering loop.");

    while (!stop)
    {
    }

    Console.WriteLine("Done.");
}
于 2012-05-25T04:37:40.357 に答える
0

ローカル変数の値のある種の最適化のように見えます-フィールドに変更すると、正常に終了します(実際のコードでは揮発性または正しいロックを使用する必要があることに注意してください):

using System;
using System.Threading;

class Program
{
    static bool stop = false;
    static void Main(string[] args)
    {

        new Thread(() =>
        {
            Thread.Sleep(1000);
            stop = true;
            Console.WriteLine("Set \"stop\" to true.");

        }).Start();

        Console.WriteLine("Entering loop.");

        while (!stop)
        {
        }

        Console.WriteLine("Done.");
    }
}
于 2012-05-25T04:53:08.703 に答える