9

我正在考虑在多线程 Win 服务中使用单例进行日志记录,并想知道我可能遇到的一些问题。我已经设置了 get 实例来处理同步

    private static volatile Logging _instance;
    private static object _syncRoot = new object();

    private Logging(){}
    public static Logging Instance
    {
        get
        {
            if (_instance==null)
            {
                lock(_syncRoot)
                {
                    if (_instance == null)
                    {
                        _instance = new Logging();
                    }
                }
            }
            return _instance;
        }
    }

还有什么我可能需要担心的吗?

4

8 回答 8

13

这对我来说看起来很不错。

有关详细信息,请参阅在 C# 中实现单例模式

编辑:不过,应该可能把回报放在锁里。

于 2009-04-07T17:04:04.807 回答
12

这比其他任何东西都更具信息性。

您发布的是双重检查锁定算法-据我所知,您发布的内容将起作用。(从 Java 1.5 开始,它也可以在那里工作。)但是,它非常脆弱——如果你弄错了,你可能会引入非常微妙的竞争条件。

我通常更喜欢在静态初始化器中初始化单例:

public class Singleton
{
    private static readonly Singleton instance = new Singleton();

    public static Singleton Instance
    {
        get { return instance; }
    }

    private Singleton()
    {
        // Do stuff
    }
}

(如果您想要一点额外的懒惰,请添加一个静态构造函数。)

这种模式更容易正确,而且在大多数情况下也一样。

在我的C# 单例实现页面上有更多详细信息(也由 Michael 链接)。

至于危险——我想说最大的问题是你失去了可测试性。对于日志记录来说可能还不错

于 2009-04-07T17:16:39.160 回答
3

单例有可能成为访问该类所体现的资源的瓶颈,并强制顺序访问原本可以并行使用的资源。

在这种情况下,这可能不是一件坏事,因为您不希望多个项目同时写入您的文件,即使这样我也不认为您的实现会产生这种结果。但这是需要注意的。

于 2009-04-07T17:06:15.660 回答
2

您需要确保记录器中的每个方法都可以安全地并发运行,即它们不会在没有适当锁定的情况下写入共享状态。

于 2009-04-07T17:55:58.147 回答
1

您正在使用被认为是反模式的双重检查锁定。Wikipedia有针对不同语言的带有和不带有延迟初始化的模式。

创建单例实例后,您当然必须确保所有方法都是线程安全的。

于 2009-04-07T17:08:26.390 回答
1

更好的建议是在单线程设置步骤中建立记录器,因此可以保证在您需要时它就在那里。在 Windows 服务中,OnStart 是执行此操作的好地方。

您拥有的另一个选择是使用 System.Threading.Interlocked.CompareExchange(T%, T, T) : T 方法来切换。它不那么令人困惑,并且可以保证工作。

System.Threading.Interlocked.CompareExchange<Logging>(_instance, null, new Logging());
于 2009-04-07T17:17:14.730 回答
1

如果您使用双重检查锁定模式并希望它适用于所有内存模型,则需要首先检查是否需要使用 Thread.VolatileRead() 存在一些争论。可以在http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/b1932d46-877f-41f1-bb9d-b4992f29cedc/阅读辩论的示例。

也就是说,我通常从上面使用 Jon Skeet 的解决方案。

于 2009-04-28T22:50:41.543 回答
0

我认为如果 Logging 实例方法是线程安全的,则无需担心。

于 2009-04-07T17:04:45.790 回答