首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >写入日志时C#锁问题

写入日志时C#锁问题
EN

Stack Overflow用户
提问于 2017-03-30 18:21:10
回答 2查看 1.9K关注 0票数 0

我有一个类,它以编程方式使用Nlog框架创建日志。我有几个进程同时运行并创建它们的日志。我在类的构造函数中添加了一个锁,就像两个线程试图同时创建一个文件一样,这导致了一些恼人的错误(比如只创建一个日志)。

这似乎解决了这个问题。然而,现在我在写日志时遇到了同样的问题,而使用锁也没有帮助。这是全班同学。

代码语言:javascript
复制
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");
            }
        }
    }

在我的客户端代码中,我运行两个线程,每个线程运行一个进程,如下所示:

代码语言:javascript
复制
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,然后没有其他输出。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-30 19:51:47

也许是这样的:

代码语言:javascript
复制
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

票数 1
EN

Stack Overflow用户

发布于 2017-03-30 18:26:56

这是因为lock()语法编译为Monitor.EnterMonitor.Leave - Monitor.Enter,如果当前线程无法锁定对象,则Monitor.Enter将使其处于休眠状态,并在调用Monitor.Leave时唤醒所有等待的线程。

您的问题是,您的第二个线程在尝试锁定对象之前必须经过额外的唤醒时间,此时刚刚释放锁的线程已经再次锁定它。

如果您希望您的例程只锁定非常短的时间(太短而不想睡觉,等待线程),则使用SpinLock代替。这个类会让每个线程继续在循环中尝试锁,直到它成功,而不是休眠。这意味着它使用更多的CPU (因此在笔记本电脑上使用更多的电池电量),这就是为什么您锁定的代码必须运行非常短的时间。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43125584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档