我有一个使用Nlog框架以编程方式创建日志的类。我有几个进程在运行并同时创建它们的日志。我在类的构造函数中添加了一个锁,就像之前两个线程试图同时创建一个文件一样,这导致了一些恼人的错误(比如只创建一个日志)。
这似乎解决了这个问题。但是现在我在写入日志时遇到了同样的问题,并且使用锁定没有帮助。这是班级。
var log = new CwiLogger(@"C:\Users\jma\Documents\ProgrammingJunk\logTest", "Log2.txt", "Log2");
for (int i = 0; i < 100; i++)
{
log.AddToLog("Log2 " + i);
}
在我的客户端代码中,我运行两个线程,每个线程运行一个如下所示的进程:
on_load
我只使用log1作为一个而log2作为另一个。
在我的输出中。 2个日志中的一个总是成功计数到99,而另一个得到4-5,然后没有其他输出。
答案 0 :(得分:1)
这是因为lock()语法编译为Monitor.Enter
而Monitor.Leave
- Monitor.Enter
将使当前线程无法锁定对象,线程持有锁和然后在调用Monitor.Leave
时唤醒所有等待的线程。
你的问题是你的第二个线程在它可以尝试锁定对象之前必须经过额外的唤醒时间,到那时刚刚释放锁的线程已经再次锁定它。
如果您希望您的例程仅在非常短的时间内锁定(太短而不想等待休眠等待线程),请使用SpinLock
代替。这个类让每个线程继续在循环中尝试锁,直到它成功而不是睡眠。这意味着它使用更多的CPU(因此笔记本电脑上的电池电量更多),这就是你锁定的代码必须运行很短时间的原因。
答案 1 :(得分:1)
也许是这样的:
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