5

2行のコードを交換すると、2つの異なる結果が得られます(Console.Write() one で done = true

done = true と入力すると、まず、結果は次のようになります: True

それ以外の場合、最初に Console.WriteLine() を配置すると、結果は次のようになります: False False

なんで?( bool 変数が static であることをよく確認してください! )

using System;
using System.Threading;

class Program
{
    static bool done;

    static void Main(string[] args)
    {
        new Thread(test).Start();
        test();
    }

    static void test()
    {
        if (!done)
        {
            done = true;
            Console.WriteLine(done);
        }
    }
}
4

4 に答える 4

8

私の予想ではConsole.WriteLine、 への 2 番目の呼び出しが実行される可能性がある間、スレッドをビジー状態に保つのに十分な作業になるでしょうtest()

したがって、基本的に への呼び出しは、2 番目の呼び出しがテストしてまだ として設定されていることを確認できるように、 の設定を十分にWriteLine遅らせます。donetestdonefalse

コンソールへの書き込みの前に示されているようにそのままにしておくと、done = true;これはほぼ瞬時に設定されるため、test への 2 番目の呼び出しは にdone設定されていることがわかりtrue、実行されませんConsole.WriteLine

すべてが理にかなっていることを願っています。


あなたの質問に非常によく似たコードを含むこれを見つけました。このページからまだ質問を受け取っていない場合は、この効果の原因をより詳細に説明しているので、一読することをお勧めします.

次のキー抽出を使用します。

シングル プロセッサのコンピューターでは、スレッド スケジューラがタイム スライスを実行し、アクティブな各スレッド間で実行をすばやく切り替えます。Windows では、タイム スライスは通常、数十ミリ秒の領域にあります。これは、あるスレッドと別のスレッド間でコンテキストを実際に切り替える際の CPU オーバーヘッド (通常は数マイクロ秒の領域) よりもはるかに大きくなります。

したがって、本質的に への呼び出しは、余分なスレッドが続行することを許可される (そして最終的にフラグConsole.WriteLineを設定する) 前に、メイン スレッドが別のスレッドを実行する時間であるとプロセッサが判断するのに十分な時間がかかります。done

于 2012-08-17T08:17:18.777 に答える
4

コードはスレッド セーフではないため、結果は予測できません。

次のように、静的ブール値の読み取り/書き込み時にアクセスをロックする必要があります。

    static bool done;
    static readonly object _mylock = new object();
    static void Main()
    {
        //Application.EnableVisualStyles();
        //Application.SetCompatibleTextRenderingDefault(false);
        //Application.Run(new Form1());
        new Thread(test).Start();
        test();
        Console.ReadKey();
    }

    static void test()
    {
        lock (_mylock)
        {
            if (!done)
            {
                Console.WriteLine(done);
                done = true;
            }
        }
    }

編集:読み取り専用@d4wnに感謝

于 2012-08-17T08:24:19.803 に答える
1

スケジューラが の呼び出し後に 1 つのスレッドから CPU 時間をカットし、それを他のスレッドに渡したように見えます。Console.Writeline以前doneはすべて に設定されていましたtrue

割り当てる前に呼び出すと、常に印刷されると確信していますか? 私の理解では、これはかなりランダムなはずです。False\nFalseConsole.Writelinedone = true;

于 2012-08-17T08:19:40.737 に答える
0

共有スレッドの1つが共有変数にアクセスするたびに、同期化手法の1つによって明示的に保護する必要があります。環境(clr ..)は私たちのためにそれを行いません、マルチスレッドの可能な全体の複雑さを引き起こすので、それは不可能でしょう。したがって、この明確に責任があり、簡単ではないタスクは、開発者がマルチスレッドコードを記述して実行する必要があります。

そこには必要な情報がたくさんあると思います: スレッド同期(C#プログラミングガイド)

于 2012-08-17T14:56:10.370 に答える