2012-12-03 30 views
1

我写了一个简单的多线程片段,让我自己习惯了这个概念。C#多线程行为

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(); 

我在输出控制台窗口中看到的是

enter image description here

我只是不明白为什么有时螺纹饰以红色本身可能会变成白色或浅灰色(任何)。你能帮助启发这个想法吗?

在此先感谢。

回答

7

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

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 statement确保只有之一在任何给定时间在critical section中的线程:

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) 
    ... 
+2

这个实现的唯一缺点是,如果创建了类的2个实例,它们将不会相互锁定。由于控制台是静态的,因此使用静态对象锁定可能会更好。 –

+0

@BobVale:好点,改变它。 – Heinzi

3

您正在调用Console.ResetColor();,它将颜色设置回默认值(灰色)。因为您有两个线程同时写入到控制台,有时一个线程在之后重置颜色,而另一个线程设置它,但之前另一个线程打印。

您可以使用thread synchronization来解决此问题。

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)); 
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();