ColoredConsoleAppender线程安全吗?
我有一个多线程控制台应用程序,在其中我使用log4net.Appender.ColoredConsoleAppender
来获取打印在控制台窗口中的错误消息。
我还使用此处介绍的非阻塞控制台阅读器:https://stackoverflow.com/a/18342182/1688642
有时,应用程序会阻塞,然后在控制台中按回车键(Enter)可以消除死锁。这总是跟在log4net上的错误(通过ColoredConsoleAppender)。我怀疑控制台阅读器中的Console.ReadLine和coloredConsoleAppender内部的文字之间存在死锁(这不是简单的Console.WriteLine)。
我查看了ColoredConsoleAppender的源代码,它比我想象的要复杂得多,我怀疑它不是线程安全的。
我还阅读了http://blogs.microsoft.co.il/dorony/2012/09/12/consolereadkey-net-45-changes-may-deadlock-your-system/中描述的Console.ReadLine和Console.WriteLine之间可能发生的潜在死锁。但是我得出的结论是,这不是同一个问题。
更新1: 下面的代码是一个说明,不是真实的代码。而且此代码不会死锁....
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using log4net;
using log4net.Config;
...
class Program
{
static void Main(string[] args)
{
var exeLocation = new FileInfo(Assembly.GetEntryAssembly().Location);
var appConfig = new FileInfo(Path.Combine(exeLocation.DirectoryName, Assembly.GetEntryAssembly().GetName().Name + ".exe.config"));
XmlConfigurator.Configure(appConfig);
// Start two threads that writes log messages
Thread t1 = new Thread(ThreadLoop);
t1.Start("T1");
Thread t2 = new Thread(ThreadLoop);
t2.Start("T2");
ILog log = LogManager.GetLogger("MAIN_LOG");
Console.Write("$ ");
while (true)
{
string line;
if (Reader.TryReadLine(out line, 100))
{
bool handled = ParseAndExecuteCommand(line);
if (!handled)
{
Console.WriteLine("Unknown command (type 'h' to get help).");
}
Console.Write("$ ");
}
log.Info($"Info from main {Environment.TickCount}");
Console.WriteLine($"Console.WriteLine from main {Environment.TickCount}");
}
}
private static void ThreadLoop(object name)
{
while (true)
{
Thread.Sleep(1000);
ILog log = LogManager.GetLogger("THREAD_LOG");
log.Info($"Info from thread {name} {Environment.TickCount}");
log.Warn($"Warning from thread {name} {Environment.TickCount}");
log.Error($"Error from thread {name} {Environment.TickCount}");
Console.WriteLine($"Console.WriteLine from thread {name} {Environment.TickCount}");
}
}
下面是App.config中的log4net配置:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
<threshold value="ERROR" />
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
</configuration>
答案 0 :(得分:0)
我已找到问题的原因。它与ColoredConsoleAppender不相关。这是Windows Command提示符的错误/功能,导致该问题。
如果在命令提示符下进入选择模式,则所有输出均被阻止(!)。如果启用了快速编辑模式,则只需在控制台窗口中单击即可。然后,文本标记将变为一个小的填充矩形,指示控制台现在处于选择模式。不容易发现!
问题描述如下: Why is my command prompt freezing on Windows 10?
我已经使用多个主题广泛测试了ColoredConsoleAppender,但没有发现任何死锁。我已经阅读了追加程序的源代码。
ColoredConsoleAppender不是线程安全的,但是我发现的唯一真正的同步问题是文本颜色混合在一起。附加程序完成的颜色更改可能会影响正在写入控制台的其他线程。
可在以下位置找到附加程序的源代码:
https://github.com/apache/logging-log4net/blob/master/src/Appender/ColoredConsoleAppender.cs
更新:ManagedColoredConsoleAppender(https://logging.apache.org/log4net/log4net-1.2.13/release/sdk/log4net.Appender.ManagedColoredConsoleAppender.html)是更好的选择。
当控制台进入选择模式时,它仍然会阻塞,但是它使用标准的Console.Out和Console.Error TextWriters。这样就可以编写可通过Console.SetOut()和Console.SetError()设置的非阻塞TextWriter。 ManagedColoredConsoleAppender将使用新的TextWriter,而ColoredConsoleAppender将不使用。