Kabuky
Kabuky

Reputation: 127

C# Multi-threading behavior

I wrote a simple multi-threading snippet just to get myself used to this concept.

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

What I saw in my output console window is

enter image description here

I just don't understand why sometimes the thread decorated with Red color could change itself to white or light gray color (whatsoever). Could you please help enlighten this mind?

Thanks in advance.

Upvotes: 1

Views: 404

Answers (4)

Heinzi
Heinzi

Reputation: 172260

Your code block is not atomic. This means that the two threads can intertwine. Example:

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

If you want the threads' actions to be atomic, i.e. uninterruptable, you need to use locking:

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

The lock statement ensures that only one of the threads in in the critical section at any given time:

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

Upvotes: 7

Bob Vale
Bob Vale

Reputation: 18474

Because

  • Thread 1 executes: Console.ForegroundColor = color;
  • Thread 2 executes: Console.ResetColor();
  • Thread 1 executes: Console.WriteLine("Thread " + color.ToString() + " : " + i);

You could use a lock to protect against this.

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

Upvotes: 5

thumbmunkeys
thumbmunkeys

Reputation: 20764

You have to lock the segment where you set the console color until you print your text.

A thread might interrupt in between and reset the color before you print your text.

change your code like this:

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

Upvotes: 1

user27414
user27414

Reputation:

You are calling Console.ResetColor();, which sets the color back to the default (gray). Because you have two threads writing to the console at the same time, sometimes one thread resets the color after the other thread sets it, but before the other thread prints.

You can resolve this using thread synchronization.

Upvotes: 3

Related Questions