在多线程应用程序中使用Singleton有什么危险

时间:2009-04-07 16:59:42

标签: c# .net multithreading singleton

我正在寻找在多线程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;
        }
    }

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

8 个答案:

答案 0 :(得分:13)

这对我来说非常好。

有关详细信息,请参阅Implementing the Singleton Pattern in C#

编辑:应该把回报放在锁内。

答案 1 :(得分: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# singleton implementation page上有更多细节(也由迈克尔联系)。

至于危险 - 我说最大的问题是你失去了可测试性。可能不适合记录。

答案 2 :(得分:3)

Singleton有可能成为访问该类所包含的资源的瓶颈,并强制顺序访问可以并行使用的资源。

在这种情况下,这可能不是一件坏事,因为您不希望同一时刻有多个项目写入您的文件,即便如此,我认为您的实现不会产生这种结果。但这是值得注意的事情。

答案 3 :(得分:2)

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

答案 4 :(得分:1)

您正在使用double-checked locking被视为反模式的内容。 Wikipedia具有针对不同语言进行延迟初始化和不进行初始化的模式。

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

答案 5 :(得分:1)

更好的建议是在单线程设置步骤中建立记录器,因此保证在您需要时存在。在Windows服务中,OnStart是一个很好的地方。

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

System.Threading.Interlocked.CompareExchange<Logging>(_instance, null, new Logging());

答案 6 :(得分:1)

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

那就是说,我通常使用Jon Skeet的解决方案。

答案 7 :(得分:0)

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