Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing console color not working exactly in multithreaded applications

I am working on multithreaded application(a server) which is basically a console application. In which I show processing log to console which is by default in white color. but on successful transaction I show the text in green and on unsuccessful transaction I show text in red. So I have three separate function in Program.cs for this.

For simple log

public static void Write(string text)
{
        try
        {
            Console.Out.Write(text);
        }
        catch (Exception)
        { }
    }

For unsuccessful transaction I change color to red, then print and then back to white

    public static void WriteError(string text)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("\t" + text);
        Console.ForegroundColor = ConsoleColor.White;
    }

For successful Transaction I change color to green, then print and then back to white

    public static void WriteSuccess(string text)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine("\t" + text);
        Console.ForegroundColor = ConsoleColor.White;

    }

The problem is when more than 200 clients connected and the log of transactions of each client is printing on console. And when I change color like green for single line it cause many other lines of normal log to green as well. So please tell me how can I solve this problem.

like image 335
M Naeem Ashraf Avatar asked Dec 13 '12 14:12

M Naeem Ashraf


2 Answers

If your class is the only one that is writing to the console, then locking on a single private object, as others mentioned, will work.

But if there are other writers, you will also need to synchronize with them, otherwise they could write while you're inside the lock. If you look at the implementation of Console, you will notice that Console.Out is a SyncTextWriter, which synchronizes on itself (using [MethodImplAttribute(MethodImplOptions.Synchronized)]). This means that if you use that as your synchronization object, you will be synchronized with other writers:

lock (Console.Out)
{
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("\t" + text);
    Console.ForegroundColor = ConsoleColor.White;
}

This will still not work correctly if the other writers also set colors and use their own synchronization object. But it will work if the other writers also synchronize on Console.Out.

The problem with this approach is that it relies on implementation details, but I'm not aware of any better solution.

like image 199
svick Avatar answered Nov 04 '22 15:11

svick


There is your problem:

    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("\t" + text);

You set the color, another thread interrupts, sets the color to something else and then you print the text (in the wrong color).

You need to protect the section with a lock:

 static object lockObj = new object();

 public static void WriteError(string text)
 {
    lock(lockObj)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("\t" + text);
        Console.ForegroundColor = ConsoleColor.White;
    }
 }

The same thing you have to do for WriteSuccess(...)

like image 12
thumbmunkeys Avatar answered Nov 04 '22 14:11

thumbmunkeys