c# - 将位置字符串更改为 const 会破坏我的记录器类

标签 c# multithreading mono constants readonly

最近我编写的一个简单的 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) block 。成功调用 Log(queue.Dequeue()); 一次后,记录器线程似乎只是关闭或暂停。

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

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

谢谢!

最佳答案

这是区别:

常量是在文件的元数据中创建的,因此当您运行类时,该值已经存在。

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

要初始化的第一个静态对象是记录器:

public static readonly TimingLogger Logger = new TimingLogger();

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

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

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

或者简单地将路径放在 Logger 之前。

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

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

关于c# - 将位置字符串更改为 const 会破坏我的记录器类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29792295/

相关文章:

c# - 如何根据年份获取一个月中的总天数?

c# - 存储为字符串的脚本的 IronPython 依赖项

iphone - 为什么我更愿意为每个新线程或 NSOperation 创建一个 NSManagedObjectContext 而不是在主线程上调用核心数据?

multithreading - 在 Kotlin 中停止线程

c# - 无需单独安装 GTK# 的 GTK# .NET 应用程序

.net - .NET/Mono 性能与 JVM 相比如何?

c# - MongoDB C# .Net 驱动程序 2.0 版基于位置的查询

c# - 逐帧播放mp3

c# - begin/async tcplistener 是如何工作的

c# - 如何在 Ubuntu 14.04.3 LTS 上安装/配置 mod_mono?