我正在编写一个C#应用程序。 我有一个(某种类型的)日志记录类,这个日志记录类将被许多线程使用。 如何使这个类是线程安全的? 我应该将其作为单例模式吗? 那么最佳实践是什么? 是否有文档可以阅读以了解如何使其线程安全?
谢谢。
我正在编写一个C#应用程序。 我有一个(某种类型的)日志记录类,这个日志记录类将被许多线程使用。 如何使这个类是线程安全的? 我应该将其作为单例模式吗? 那么最佳实践是什么? 是否有文档可以阅读以了解如何使其线程安全?
谢谢。
在C#中,任何对象都可以用于保护“关键段”,换句话说,即不能同时由两个线程执行的代码。
例如,以下代码将同步访问SharedLogger.Write方法,因此在任何给定时间只有一个线程记录消息。
public class SharedLogger : ILogger
{
public static SharedLogger Instance = new SharedLogger();
public void Write(string s)
{
lock (_lock)
{
_writer.Write(s);
}
}
private SharedLogger()
{
_writer = new LogWriter();
}
private object _lock = new object();
private LogWriter _writer;
}
public class SharedLogger : ILogger
{
public static SharedLogger Instance = new SharedLogger();
public void Write(string s)
{
lock (_lock)
{
_writer.Write(s);
}
}
private SharedLogger()
{
_writer = new LogWriter();
}
private object _lock;
private LogWriter _writer;
}
Instance
静态变量定义了一个 SharedLogger
的单例实例,并通过私有构造函数防止其他人实例化该类。这就是单例模式的精髓,但我强烈建议在深入学习之前阅读并遵循 Jon Skeet 关于 C#中的单例 的建议。SharedLogger.Instance.Write("log message");
整个“Instance”部分看起来不太对,但考虑到实现方式,无法避免。相反,考虑采用以下替代方案:
public static class SharedLogger
{
private static LogWriter _writer = new LogWriter();
private static object _lock = new object();
public static void Write(string s)
{
lock (_lock)
{
_writer.Write(s);
}
}
}
SharedLogger.Write("log message");
使用这种方法编程会更加简单。
重点不是贬低以前的解决方案,而是建议您选择任何解决方案时,可用性是一个重要的方面不容忽视。一个好的、易于使用的API可以使代码编写更简单、更优雅、更易于维护。
针对这个问题,我建议使用市面上现成的记录器,因为有很多记录器非常稳定且易于使用,不需要自己编写。 我推荐使用Log4Net。
lock
块中更改对象的状态。在我看来,上面提供的代码不再是线程安全的了: 在之前的解决方案中,您必须实例化一个新的SharedLogger对象,并且每个对象都有一个Write方法。
现在你只有一个Write方法,所有线程都会使用它,例如:
线程1: SharedLogger.Write("线程1")
线程2: SharedLogger.Write("线程2");
public static void Write(string s)
{
// thread 1 is interrupted here <=
lock (_lock)
{
_writer.Write(s);
}
}
线程2覆盖了线程1的消息,并被线程1打断
线程1获取锁并写入“Thread 2”
如果我有错误,请纠正我...