Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infrequent hangs in a multi-threaded C# console application when using Console.Writeline() or Console.Write()

I have written a console application that makes use of console.write and console.writeline to provide some logging. The application is a server application that uses asynchronous beginacceptconnection() and beginread() ( Sockets ) for communication. Occasionally i get reports of it hanging and from the limited debug i can do i am able to see the problem being Console.Writeline() or Console.write().

Being multi-threaded I have been careful to have a lock around the logging class so only one thread can log a message at once.....when I've caught a hang all i get are threads blocking on the lock and VS reporting that the control has passed into Console.Write and it is waiting for it to come back....it never does.

A couple of days ago i got another report of a failure but this time during bootup....where no asynch connections have yet been kicked off( the main thread does spawn a thread to bootup though ) and I was sent a picture.....see below.( i added the begin and end critical section lines to prevent this and it did not )

// Logging Class

public class Logging
{
    // Lock to make the logging class thread safe.
    static readonly object _locker = new object();

    public delegate void msgHandlerWriteLineDelegate(string msg, Color col);
    public static event msgHandlerWriteLineDelegate themsgHandlerWriteLineDelegate;

    public delegate void msgHandlerWriteDelegate(string msg, Color col);
    public static event msgHandlerWriteDelegate themsgHandlerWriteDelegate;

    public static void Write(string a, Color Col)
    {
        if (themsgHandlerWriteDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteDelegate(a, Col);
            }
        }
    }

    public static void Write(string a)
    {
        if (themsgHandlerWriteDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteDelegate(a, Color.Black);
            }
        }
    }

    public static void WriteLine(string a, Color Col)
    {
        if (themsgHandlerWriteLineDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteLineDelegate(a, Col);
            }
        }
    }

    public static void WriteLine(string a)
    {
        if (themsgHandlerWriteLineDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteLineDelegate(a, Color.Black);
            }
        }
    }

    // Console Methods That implement the delegates in my logging class.

    public static void ConsoleWriteLine(string message, Color Col)
    {
        try
        {
            if (Col == Color.Black)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
            }
            else
            {
                Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), Col.Name);
            }
            Thread.BeginCriticalRegion();
            Console.WriteLine(message);
            Thread.EndCriticalRegion();
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        catch (ThreadAbortException ex)
        {
            Console.WriteLine("ThreadAbortException : " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception : " + ex.Message);
        }
    }

    public static void ConsoleWrite(string message, Color Col)
    {
        try
        {
            if (Col == Color.Black)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
            }
            else
            {
                Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), Col.Name);
            }
            Thread.BeginCriticalRegion();
            Console.Write(message);//**THIS IS WHERE IS HANGS...IT NEVER RETURNS **
            Thread.EndCriticalRegion();
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        catch (ThreadAbortException ex)
        {
            Console.WriteLine("ThreadAbortException : " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception : " + ex.Message);
        }
    }

    public static void ConsoleUpdate(string message)
    {
        try
        {
            Thread.BeginCriticalRegion();
            Console.WriteLine(message);//**THIS IS WHERE IS HANGS...IT NEVER RETURNS **
            Thread.EndCriticalRegion();
        }
        catch (ThreadAbortException ex)
        {
            Console.WriteLine("ThreadAbortException : " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception : " + ex.Message);
        }
    }

    // The main method...subscribes to delegates and spawns a thread to boot HW..main thread then exits.

    public static void Main()
    {
        Logging.themsgHandlerWriteDelegate += new Logging.msgHandlerWriteDelegate(ConsoleWrite);
        Logging.themsgHandlerWriteLineDelegate += new Logging.msgHandlerWriteLineDelegate(ConsoleWriteLine);
        Logging.themsgHandlerUpdateDelegate += new Logging.msgHandlerUpdateDelegate(ConsoleUpdate);
    }
}

public class ClassOnOtherThread
{
    // In a different class running on a different thread the following line occasionly invokes the error:

    private void BootHw(string Resource, string Resource2)
    {
        Logging.Write("\t\t[");
    }
}

My reading of the MSDN suggests Console.WriteLine and Console.Write are threadsafe and therefore i don't actually need a lock around it....i also can't believe it Microsoft's code is wrong(;-) and so I am guessing it is some interaction my code is doing which creates the error.

Now my question : Should i be doing anything to prevent Console.WriteLine and Console.Write being interrupted?...it is my guess that something it interrupting it...but i don't really know that!!

Any help would me very much appreciated.

Regards,

Gordon.

like image 940
Gordon Roxburgh Avatar asked Jun 27 '11 20:06

Gordon Roxburgh


2 Answers

I had the same problem.

I was using console.readkey() in main thread to prevent closing application in debug mode.

After I replaced it with an infinite loop my problem was solved.

like image 59
mostafa bafandegan Avatar answered Sep 20 '22 12:09

mostafa bafandegan


You should solve your problem by removing the locks around the logging. The logging is done via Console.WriteLine which is synchronized (and thread safe). You are possibly causing a deadlock through your own locking mechanism (though I can't verify without seeing the code).

like image 22
Ethan Cabiac Avatar answered Sep 21 '22 12:09

Ethan Cabiac