我编写了一个控制台应用程序,它使用console.write和console.writeline来提供一些日志记录。该应用程序是一个服务器应用程序,它使用异步beginacceptconnection()和beginread()(套接字)进行通信。偶尔我会得到挂起的报告,从有限的调试我可以做到,我能够看到问题是Console.Writeline()或Console.write()。
多线程我一直小心锁定日志记录类,所以只有一个线程可以一次记录消息.....当我抓到一个挂起时,我得到的是线程阻塞锁定和VS报告控件已经传递到Console.Write并且它正在等待它返回....它永远不会。
几天前我得到了另一个失败的报告,但这次是在启动时....没有asynch连接尚未启动(主线程确实产生了一个线程来启动)然后我被发送了图片.....见下文。(我添加了开始和结束关键部分线以防止这种情况,但它没有)
// 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[");
}
}
我对MSDN的阅读表明Console.WriteLine和Console.Write是线程安全的,因此我实际上并不需要锁定它....我也无法相信它的代码是错误的(;-)和所以我猜这是我的代码正在进行的一些交互,这会产生错误。
现在我的问题:我应该做些什么来阻止Console.WriteLine和Console.Write被中断?...我猜这是它打断它的东西......但我真的不知道!! / p>
任何帮助都非常感谢。
此致
戈登。
答案 0 :(得分:8)
我遇到了同样的问题。
我在主线程中使用console.readkey()
来阻止在调试模式下关闭应用程序。
我用无限循环替换它之后我的问题就解决了。
答案 1 :(得分:2)
Consol.Writeline()
是线程安全的。所以
我一直小心锁定日志记录类
这不应该是必要的,很可能是死锁的遗留问题。没有任何代码示例,就不可能说出是/如何/什么。
所以我猜这是我的代码正在进行的一些交互,这会产生错误。
很可能。
这是我的猜测,它打断了它......
没有
答案 2 :(得分:2)
您应该通过删除日志记录周围的锁来解决您的问题。日志记录通过同步(和线程安全)的Console.WriteLine
完成。您可能通过自己的锁定机制导致死锁(虽然我无法在不看代码的情况下进行验证)。
答案 3 :(得分:2)
这是一个很长的镜头,但我想知道你是否用ToString()方法锁定的对象调用Console.WriteLine。如果是这样,您可以让自己处于与Console.WriteLine内部锁定相关的死锁状态。
我曾将this bug report发布到Microsoft Connect,但遗憾的是他们拒绝修复它。
答案 4 :(得分:1)
我猜你的应用程序是由另一个重定向stderr和stdout的进程启动的。如果您的“观察者”进程对同一线程上的两个流使用ReadToEnd(),则可能会死锁。
死锁的另一个选择是通过stdin发送子进程输入,而stdin又启动另一个进程,该进程有一个无限期等待输入的控制台。这一次发生在wmic.exe上,当stdin被重定向时会阻塞。
如果您使用过您的日志类,我怀疑您使用自己的日志类更改了底层的Console.Out。请至少发布您的应用程序挂起的callstack,以便我们分析一些内容。如果用自己的控制台替换控制台流,有很多方法可以用脚射击自己。
此致, Alois Kraus