静态记录器类考虑

时间:2014-08-24 19:16:54

标签: c#

我发现了一些记录器类,我不确定这个类是否真的是线程安全的。确实是Log方法实现了锁,但多线程对类本身的访问不会引发问题?它认为我因为TextWriter tw是静态的,所以它意味着类只有tw的一个副本,并且在每个线程中访问它会引发问题吗?顺便问一下,请看看你有没有其他异议?:

public static class Logger
{
    static readonly TextWriter tw; 
    private static readonly object _syncObject = new object();

    static Logger(string SPath)
    {
        tw = TextWriter.Synchronized(File.AppendText(SPath + "\\Log.txt")); 
    }


    public static void Write(string logMessage)
    {
        try
        {
            Log(logMessage, tw);
        }
        catch (IOException e)
        {
            tw.Close();
        }
    }

    public static void Log(string logMessage, TextWriter w)    {
   // only one thread can own this lock, so other threads
   // entering this method will wait here until lock is
   // available.
   lock(_syncObject) {
      w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
          DateTime.Now.ToLongDateString());
      w.WriteLine("  :");
      w.WriteLine("  :{0}", logMessage);
      w.WriteLine("-------------------------------");
      // Update the underlying file.
      w.Flush();
   }
}
}

第二个版本用于进一步的dicsuss目的:

 public static class Logger
    {
        static StreamWriter  sw; 
        private static readonly object _syncObject = new object();

        static Logger(string SPath)
        {
           lock(_syncObject)
           {
           StreamWriter sw = File.AppendText(SPath));
           }    
    }
    ....

2 个答案:

答案 0 :(得分:0)

它是线程安全的,因为每个路径都使用Log静态方法,该方法在静态_syncObject上使用锁定。这意味着如果其他人正在记录,那么尝试记录(..)的每个线程都将阻塞。

但是,如果直接调用Log方法而不是Write方法,并传入其他线程正在使用的TextWriter,那么这是不安全的。

答案 1 :(得分:0)

首先,TextWriter是一个抽象类,因此真实实例可能是任何派生类。 TextWriter上的documentation不保证TextWriter实施的线程安全性:

  

不保证所有实例成员都是线程安全的。

无法保证外部锁定会带来线程安全性。例如,实现可以将线程本地存储用于其内部数据。 TextWriter.Flush可能会有所帮助,也可能没有帮助,具体取决于实现方式(但您永远不知道Log方法中的实现方式以及此实现是否在例如同一锁定下创建。“

这一切都与Log方法有关。

相反,Write的使用情况似乎很好:它根据documentation使用TextWriter.Synchronized,这是线程安全的:

  

围绕指定的TextWriter创建一个线程安全的包装器。

但请注意,同步文本编写器的线程安全性可能是也可能不是您需要的线程安全性:如果您要对Log进行连续调用,则结果不能保证是连续的在输出文件中。