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

4

11

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.

Virgil answered 27/6, 2011 at 20:45 Comment(8)
I'll post some tomorrow once i get back in the office.Virgil
Just press Ctrl+S, instant hang.Writhen
After seeing the code: there is a lot (really) that can be removed. I can't spot an obvious error but the Begin/EndCrtiticalRegion were not meant and are not needed for Console.WriteLine(). Your error is probaly in the sockets code.Brainy
Yes the begin/end critical section methods were really my attempt to fix it but it didn't work. I'm still confused how the socket code can block console.writeline()Virgil
How sure are you that it is WriteLine that hangs?Brainy
Solved a similiar issue by using ReadLine after reading answer by mostafa. Might be related to social.msdn.microsoft.com/Forums/vstudio/en-US/…Aeolis
There is a KB that is supposed to fix this but WU does not find it on my win 8.1: support.microsoft.com/en-us/kb/2805221 (CLR issue #4)Aeolis
You mentioned that you are using sockets. In my case it was WebSockets4Net lib which hangs System.IO.SyncTextWriter.WriteLine when using Console.WriteLine in socket event callbacks. Please provide info about project dependencies.Doublecross
U
8

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.

Unrig answered 11/9, 2012 at 13:52 Comment(1)
This worked for me... change ReadKey to ReadLine and it is fixed. ThanksRodge
D
2

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

Dotterel answered 27/6, 2011 at 20:52 Comment(3)
agreed but it doesn't explain why the console.writeline or console.write methods once called fail to return(thus creating the deadlock you mention )....i just get a green arrow in VS next to the line with a message saying the method was called into and has not returned....if i un-pause vs and wait 30 seconds....and then pause again it is in the same place. Regards,Virgil
the deadlock is not created by a failure of the Console.WriteLine to return (this is simply blocking). A deadlock occurs when threads fight over resources. Since you haven't posted any code, I can't tell you what you are deadlocking on.Dotterel
How does console.writeline() block then? Code now posted.Virgil
T
2

I guess your application is started by another process which does redirect stderr and stdout. If your "watcher" process uses ReadToEnd() for both streams on the same thread you can deadlock.

Another option to deadlock is to send the child process input via stdin which in turn starts another process which has a console which waits for input indefinitely. This happend once to me with wmic.exe which does block when stdin is redirected.

If you have played with your log class I suspect that you change the underlying Stream of Console.Out with your own one. Please post at least the callstack where your application is hanging so we have something to analyze. There are many ways to shoot yourself in the foot if you replace the console stream with your own one.

Yours, Alois Kraus

Tyro answered 27/6, 2011 at 20:53 Comment(5)
I have a picture but wasn't allowed to post as this is my first post on this website.Virgil
I have a picture but wasn't allowed to post as this is my first post on this website. It shows the line it hangs on the active threads and the call stack. I could send it if you think this would help? My program is a .exe that starts and spawns two threads to boot two identical sets of HW. However the failure i describe is seen when only one thread ( and one set of HW ) is booted. The main thread then exits( although i did do a t1.join but the error was still seen.Virgil
In this new thread as I boot the HW i call my logging class to display bootup messages. These static logging methods call a delegate that if a subscriber implements it will display the message....at the moment I am just writing a console app but may change it to a windows form at some point....anyway the Logging.WriteLine() method i implemented is subscribed to by a method that implements it using Console.Writeline()... occasionally when it hangs and i hit pause in VS all i see if the 1st spawned thread stuck inside the Console.Writeline() methodVirgil
it never returns......I had a quick read of the console redirection stuff you mentioned.....why would i need to do this? Is it because the main thread is not the one that is writing to the console. Regards,Virgil
Yes a screenshot of the hanging thread would help. Send it to akraus1 at gmx dot de. Is your console application started by another process which reads/redirects your output?Tyro
L
2

This is a bit of a long shot, but I wonder if you are calling Console.WriteLine with objects whose ToString() method takes a lock. If so, you can get yourself in a deadlock situation with respect to the lock taken internally by Console.WriteLine.

I once posted this bug report to Microsoft Connect, though sadly they declined to fix it.

Letrice answered 27/6, 2011 at 22:17 Comment(1)
Yes i just read your post on 'connect'...seems similar...i'll have a look at the code when in the office tomorrow.Virgil

© 2022 - 2024 — McMap. All rights reserved.