使用log4net的死锁.Appender.彩色控制台显示



ColoredConsoleAppender线程安全吗?

我有一个多线程控制台应用程序,我使用log4net.Appender.ColoredConsoleAppender在控制台窗口中打印错误消息。

我还使用了这里描述的非阻塞控制台读取器:https://stackoverflow.com/a/18342182/1688642

偶尔应用程序会阻塞,并在控制台中按Return键(Enter(可消除死锁。这之后总是会出现来自log4net的错误(通过ColoredConsoleAppender(。我怀疑控制台之间存在死锁。控制台读取器中的ReadLine和ColoredConsoleAppender(这不是一个简单的console.WriteLine(内部的写入。

我看过ColoredConsoleAppender的源代码,它比我想象的要复杂得多,我怀疑它不是线程安全的。

我还读到了Console之间可能发生的潜在死锁。ReadLine和控制台。WriteLine描述如下:http://blogs.microsoft.co.il/dorony/2012/09/12/consolereadkey-net-45-changes-may-deadlock-your-system/但我得出的结论是,这不是同一个问题。

更新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>

我已经找到了问题的原因。它与ColoredConsoleAppender无关。导致该问题的是Windows命令提示符的错误/功能。

如果在命令提示符中进入选择模式,则所有输出都将被阻止(!(。如果启用了"快速编辑"模式,则只需在控制台窗口内单击即可。然后,文本标记将变为一个填充的小矩形,表示控制台现在处于选择模式。不容易发现!

此处对该问题进行说明:为什么我的命令提示符在Windows 10上冻结?

我已经使用多种方法对ColoredConsoleAppender进行了广泛的测试,没有发现任何死锁。我还阅读了appender的源代码。

ColoredConsoleAppender不是线程安全的,但我发现的唯一真正的同步问题是文本颜色混淆了。appender所做的颜色更改可能会影响正在写入控制台的其他线程。

appender的源代码可以在此处找到:
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(是一个更好的选择。

当控制台进入选择模式时,它仍然会被阻止,但它使用标准控制台。输出和控制台。错误TextWriters。这样就可以编写一个可以使用Console设置的非阻塞TextWriter。SetOut((和Console。SetError((。ManagedColoredConsoleAppender将使用新的TextWriter,而ColoredConsoleAppeder将不使用。

最新更新