【问题标题】:Changing a location string to const breaks my logger class将位置字符串更改为 const 会破坏我的记录器类
【发布时间】:2015-04-22 08:50:13
【问题描述】:

我一直在努力解决最近出现的一个问题,该问题是我编写的一个简单的 logtofile 类。

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace Assets.Code
{
    class TimingLogger
    {
        public static readonly TimingLogger Logger = new TimingLogger();
        private static readonly string path = "C:\\Logs\\TimingLog.txt";
        private readonly Mutex mutex = new Mutex(false, path);
        private StreamWriter writer;
        private readonly Queue<string> queue = new Queue<string>();
        private bool isRunning;
        private readonly object obj = new object();

        private TimingLogger()
        {

        }

        public void CheckPath()
        {
            if (!File.Exists(path))
            {
                File.Create(path);
            }
        }

        public void Run()
        {
            isRunning = true;
            while (isRunning)
            {
                lock (obj)
                {
                    while (queue.Count <= 0)
                    {
                        Monitor.Wait(obj);
                    }
                    Log(queue.Dequeue());
                }
            }
        }

        public void Log(string line)
        {
            try
            {
                mutex.WaitOne();
                writer = File.AppendText(path);
                writer.WriteLine(line);
                writer.Close();
            }
            catch (Exception)
            {
                //throw;
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }

        public void Enqueue(string line)
        {
            lock (obj)
            {
                queue.Enqueue(line);
                Monitor.Pulse(obj);
            }
        }

        public void Stop()
        {
            isRunning = false;
        }
    }
}

直到最近,当我注意到我的日志文件没有显示我预期的数据时,这个类工作得很好。奇怪的是,我没有改变这个类的任何功能。比较旧的工作版本和我的新版本,唯一的区别是我的一些字段是privatereadonly。除此之外,string path 更改为const。令我完全困惑的是,将其改回 readonly 解决了我遇到的问题。

所以我的问题是:这到底是怎么可能的?据我所知,在这种情况下,readonly 和 const 在功能上应该没有任何区别。

在调试时,行为的变化是巨大的,尤其是在Run() 方法中。这里应该发生的是,一旦调用了Log(queue.Dequeue());,线程将离开lock 语句并再次遍历while (isRunning) 循环。这似乎很明显,对吧?但是,当我将string path 更改为const 并再次调试时,Log(queue.Dequeue()); 被传递一次,并且可以在日志文件中找到一条语句,之后它就不再执行任何其他操作。它没有再次经过while (isRunning) 并且似乎没有离开lock (obj) 块。成功调用Log(queue.Dequeue()); 一次后,记录器线程似乎只是简单地关闭或暂停。

实际上在Log 方法中抛出异常没有区别,不会抛出异常,因为日志记录本身工作正常。

我应该提到我正在将此代码与使用 Mono 的 Unity3D 5 一起使用。但是,对我来说,如此小的编辑带来的这种行为上的巨大变化似乎是不可能的。谁能解释为什么会这样?

谢谢!

【问题讨论】:

  • 我认为在邮件正文中发布的代码有点过多,但好吧,我已经添加了。
  • 这比可能会消失并让您的问题在以后变得难以理解的链接要好得多。编写记录器是一项已经解决的棘手问题。使用nLog等现有的解决方案不是更好吗?
  • 有趣的是,您应该提到这一点.我只是不明白这个问题。
  • 可能不是问题,但将 mutex.WaitOne(); 放在 try 之前 - 如果该语句引发异常,则在终结器中引发新异常(也许它应该被包装在另一个 try/catch 中) .
  • 有趣,包装'mutex.ReleaseMutex();'在 try/catch does 中显示异常,但仅在调试时。 “现在拥有互斥锁”是个例外。遗憾的是我今天没有时间进一步研究这个。更多即将到来! :)

标签: c# multithreading mono constants readonly


【解决方案1】:

这里有区别:

常量是在文件的元数据中创建的,所以当你运行你的类时,值已经存在了。

ReadOnly 是在编译时初始化的,在你的情况下,这就是诀窍,即使你先声明了路径然后是互斥体,编译器首先初始化了互斥体对象,原因如下:

您要初始化的第一个静态对象是 Logger:

public static readonly TimingLogger Logger = new TimingLogger();

因为您调用了构造函数,所以初始化了非静态成员,使 mutex 成为下一个要初始化的成员。此时你还没有初始化路径,所以 您正在使用参数 false 和 null 创建互斥对象。

如果您想遇到与使用只读的 const 相同的错误,您可以使用静态构造函数强制静态参数初始化的顺序,例如:

static TimingLogger()
{
    path = "C:\\Logs\\TimingLog.txt";
    Logger = new TimingLogger();
}

或者干脆把路径放在 Logger 之前。

如果您不想使用 const 出现错误,只需使用 null 参数更改互斥体初始化:

private readonly Mutex mutex = new Mutex(false, null);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多