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

您的代码块不是atomic。这意味着两个线程可以交织在一起。例子:

   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 语句确保在任何给定时间只有临界区中的一个线程:

   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();,它将颜色设置回默认值(灰色)。因为您有两个线程同时写入控制台,所以有时一个线程在另一个线程设置颜色之后重置颜色,但另一个线程打印之前。

您可以使用线程同步解决此问题。

于 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 回答