我有一个类,它以编程方式使用Nlog框架创建日志。我有几个进程同时运行并创建它们的日志。我在类的构造函数中添加了一个锁,就像两个线程试图同时创建一个文件一样,这导致了一些恼人的错误(比如只创建一个日志)。
这似乎解决了这个问题。然而,现在我在写日志时遇到了同样的问题,而使用锁也没有帮助。这是全班同学。
public class CwiLogger
{
private Logger _log;
private static Object createLogLock = new Object();
private static Object writeLogLock = new Object();
public CwiLogger(string logPath, string logName, string className)
{
lock (createLogLock)
{
var config = new LoggingConfiguration();
var fileTarget = new FileTarget();
config.AddTarget("file", fileTarget);
fileTarget.FileName = Path.Combine(logPath, logName);
fileTarget.Layout = "${longdate}|${level:uppercase=true}|${logger}|${message}";
var rule = new LoggingRule("*", LogLevel.Debug, fileTarget);
config.LoggingRules.Add(rule);
LogManager.Configuration = config;
this._log = LogManager.GetLogger(className);
}
}
public void AddToLog(string logText, LogLevel level = null)
{
lock (writeLogLock)
{
level = level ?? LogLevel.Info;
this._log.Log(level, logText + "\n");
}
}
}在我的客户端代码中,我运行两个线程,每个线程运行一个进程,如下所示:
var log = new CwiLogger(@"C:\Users\jma\Documents\ProgrammingJunk\logTest", "Log2.txt", "Log2");
for (int i = 0; i < 100; i++)
{
log.AddToLog("Log2 " + i);
}只有我一个使用log1,另一个使用log2。
在我的输出中。这两个日志中的一个总是成功地计数到99,而另一个则得到4-5,然后没有其他输出。
发布于 2017-03-30 19:51:47
也许是这样的:
public class CwiLogger
{
private static LoggingConfiguration _logConfig = new LoggingConfiguration();
private static Object createLogLock = new Object();
private Logger _log;
public CwiLogger(string logPath, string logName, string className)
{
lock (createLogLock)
{
var fileTarget = _logConfig.FindTargetByName(logName);
if (fileTarget == null)
{
var fileTarget = new FileTarget(logName);
fileTarget.FileName = Path.Combine(logPath, logName);
fileTarget.Layout = "${longdate}|${level:uppercase=true}|${logger}|${message}";
_logConfig.AddTarget(fileTarget);
var rule = new LoggingRule(className, LogLevel.Debug, fileTarget) { Final = true };
_logConfig.LoggingRules.Add(rule);
LogManager.Configuration = _logConfig;
}
}
this._log = LogManager.GetLogger(className);
}
public void AddToLog(string logText, LogLevel level = null)
{
level = level ?? LogLevel.Info;
this._log.Log(level, logText + "\n");
}
}或者从这里窃取一些想法:https://github.com/NLog/NLog/issues/1998
发布于 2017-03-30 18:26:56
这是因为lock()语法编译为Monitor.Enter和Monitor.Leave - Monitor.Enter,如果当前线程无法锁定对象,则Monitor.Enter将使其处于休眠状态,并在调用Monitor.Leave时唤醒所有等待的线程。
您的问题是,您的第二个线程在尝试锁定对象之前必须经过额外的唤醒时间,此时刚刚释放锁的线程已经再次锁定它。
如果您希望您的例程只锁定非常短的时间(太短而不想睡觉,等待线程),则使用SpinLock代替。这个类会让每个线程继续在循环中尝试锁,直到它成功,而不是休眠。这意味着它使用更多的CPU (因此在笔记本电脑上使用更多的电池电量),这就是为什么您锁定的代码必须运行非常短的时间。
https://stackoverflow.com/questions/43125584
复制相似问题