Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在多线程应用程序中使用单实例有什么危险_C#_.net_Multithreading_Singleton - Fatal编程技术网

C# 在多线程应用程序中使用单实例有什么危险

C# 在多线程应用程序中使用单实例有什么危险,c#,.net,multithreading,singleton,C#,.net,Multithreading,Singleton,我正在考虑在多线程Win服务中使用单例来进行日志记录,并想知道我可能会遇到哪些问题。我已经设置了get实例来处理与的同步 private static volatile Logging _instance; private static object _syncRoot = new object(); private Logging(){} public static Logging Instance { get {

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

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

我觉得很好

有关更多信息,请参阅


Edit:可能应该将返回放在锁中。

我认为如果日志实例方法是线程安全的,就不必担心。

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

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

您正在使用被认为是反模式的东西。具有针对不同语言的具有和不具有惰性初始化的模式


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

这比其他任何方法都更具信息性

您发布的是双重检查锁定算法——据我所知,您发布的将起作用。(从Java1.5开始,它也可以在那里工作。)然而,它非常脆弱——如果你有任何错误,你可能会引入非常微妙的竞争条件

我通常更喜欢在静态初始值设定项中初始化singleton:

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

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

    private Singleton()
    {
        // Do stuff
    }
}
(如果您需要一点额外的惰性,请添加一个静态构造函数。)

这种模式更容易得到正确的答案,在大多数情况下也一样

还有更多关于我的详细信息(也由Michael链接)


至于危险,我认为最大的问题是你失去了可测试性。对于日志记录来说可能还不算太糟。

更好的建议是在单线程设置步骤中建立日志记录程序,这样就可以保证在您需要它时它就在那里。在Windows服务中,OnStart是实现这一点的好地方

另一个选项是使用System.Threading.Interlocated.CompareExchange(T%,T,T):T方法进行切换。它不那么令人困惑,而且保证会起作用

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

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

对于是否需要对null use Thread.volatieread()进行第一次检查,存在一些争论如果您使用双重检查锁定模式,并希望它在所有内存型号上都能工作。有关这场辩论的一个例子,请参阅


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

在将实例与null进行比较之前先锁定。@Joel:不,这是故意的双重检查锁定。这很微妙,但它确实有效——如果你完全正确的话。呸,如果别人已经链接到我的文章,我来拉皮条又有什么意义呢?;)@乔恩,天哪。我已经引用那篇文章好几个月了,根本不知道是你写的。有趣的是,在乔恩的帖子中,链接断了:)这里是龙!“不要插手龙的事情,因为你很脆,加上番茄酱味道很好。”我宁愿它是瓶颈,也不愿意它崩溃,这就是我不得不进行大量活动时发生的事情,这就是我考虑使用单人床的原因+1为了获得良好的洞察力,使用单例是否会阻止您同时运行它们?我认为这就是重点。不,多个线程仍然可以访问单个日志实例。它的方法必须是线程安全的+“1来解决这个问题。@bob:您的双重检查锁定阻止创建多个实例(为了保证单实例性),但它不阻止多个线程的并发访问。指向您文章的链接已断开。这很令人伤心,不是吗?”?这就是患重感冒的危险。修好了,谢谢你的注意。在这里使用物业的原因是什么?使用公共静态只读字段难道还不够安全吗?@ArthurStankevich:如果您将其设置为属性,您可以在以后更改实现-例如,如果您希望在
单例
中具有不触发初始化的静态方法,可以改为在嵌套类中使用字段。(无可否认,目前他们还不能保证,但实际上我可能会在这里使用静态构造函数,这会改变时间。)基本上,我发现使用属性会给您带来更大的灵活性。我不是C#专家,但我希望每次调用都会生成一个新的日志实例。
new Logging()
部分在InterlocatedCompareExchange内部的原子检查之前执行。你说得对。这到底有多糟糕取决于日志构造函数(和初始值设定项)的语义。我认为它仍然有效,第一个建议更好。