1

この概念に慣れるために、単純なマルチスレッドスニペットを作成しました。

public void testThread(int arg1, ConsoleColor color)
    {
        for (int i = 0; i < 1000; i++)
        {
            Console.ForegroundColor = color;
            Console.WriteLine("Thread " + color.ToString() + " : " + i);
            Console.ResetColor();
            Thread.Sleep(arg1);
        }
    }

Thread t1 = new Thread(() => program.testThread(1000, ConsoleColor.Blue));
Thread t2 = new Thread(() => program.testThread(1000, ConsoleColor.Red));
t1.Start();
t2.Start();
t1.Join();
t2.Join();

出力コンソールウィンドウに表示されたのは

ここに画像の説明を入力してください

なぜ赤い色で飾られた糸が白や薄い灰色に変わることがあるのか​​、私にはわかりません。この心を啓発するのを手伝っていただけませんか?

前もって感謝します。

4

4 に答える 4

7

コードブロックはアトミックではありません。これは、2つのスレッドが絡み合う可能性があることを意味します。例:

   Thread 1 (Red)               Thread 2 (Blue)
--------------------------------------------------------------
                                 Set Color Blue
   Set Color Red         
                                 Print Text (printed in Red!)
   Print Text (printed in Red!)

スレッドのアクションをアトミック、つまり中断できないようにする場合は、ロックを使用する必要があります。

private static readonly object myLock = new object();

public void testThread(int arg1, ConsoleColor color)
{
    for (int i = 0; i < 1000; i++)
    {
        lock (myLock) {
            Console.ForegroundColor = color;
            Console.WriteLine("Thread " + color.ToString() + " : " + i);
            Console.ResetColor();
        }
        Thread.Sleep(arg1);
    }
}

lockステートメントは、常にクリティカルセクションにあるスレッドの1つだけを保証します。

   Thread 1 (Red)               Thread 2 (Blue)
--------------------------------------------------------------
                                 Enter critical section (lock)
   wait...                       Set Color Blue
                                 Print Text (printed in Red!)
                                 Reset Color
                                 Leave critical section
   Enter critical section (lock)
   ...
于 2012-12-03T16:07:44.017 に答える
5

なぜなら

  • スレッド1は実行されます:Console.ForegroundColor = color;
  • スレッド2は実行されます:Console.ResetColor();
  • スレッド1は実行されます:Console.WriteLine("Thread " + color.ToString() + " : " + i);

これを防ぐためにロックを使用できます。

private static readonly object lockObject=new object();

public void testThread(int arg1, ConsoleColor color)
{
    for (int i = 0; i < 1000; i++)
    {
        lock (lockObject) {
          Console.ForegroundColor = color;
          Console.WriteLine("Thread " + color.ToString() + " : " + i);
          Console.ResetColor();
        }
        Thread.Sleep(arg1);
    }
}

Thread t1 = new Thread(() => program.testThread(1000, ConsoleColor.Blue));
Thread t2 = new Thread(() => program.testThread(1000, ConsoleColor.Red));
t1.Start();
t2.Start();
t1.Join();
t2.Join();
于 2012-12-03T16:07:34.817 に答える
3

を呼び出しConsole.ResetColor();ています。これにより、色がデフォルト(灰色)に戻ります。2つのスレッドが同時にコンソールに書き込むため、一方のスレッドが色をリセットした、もう一方のスレッドが印刷する前に色をリセットすることがあります。

これは、スレッド同期を使用して解決できます。

于 2012-12-03T16:06:59.503 に答える
1

テキストを印刷するまで、コンソールの色を設定したセグメントをロックする必要があります。

テキストを印刷する前に、スレッドが途中で中断して色をリセットする場合があります。

次のようにコードを変更します。

public void testThread(int arg1, ConsoleColor color, object lockObj)
{
    for (int i = 0; i < 1000; i++)
    {
        lock(lockObj)
        {
            Console.ForegroundColor = color;
            Console.WriteLine("Thread " + color.ToString() + " : " + i);
            Console.ResetColor();
        }
        Thread.Sleep(arg1);
    }
}

var lockObj = new object();
Thread t1 = new Thread(() => program.testThread(1000, ConsoleColor.Blue, lockObj));
Thread t2 = new Thread(() => program.testThread(1000, ConsoleColor.Red, lockObj));
于 2012-12-03T16:07:19.160 に答える