Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.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#_Constructor_Singleton_Multithreading - Fatal编程技术网

静态初始化保证单线程安全?(C#)

静态初始化保证单线程安全?(C#),c#,constructor,singleton,multithreading,C#,Constructor,Singleton,Multithreading,可能重复: Jon Skeet的优秀文章at和我读过的其他文章清楚地表明,双重检查锁定在C#和Java中都不起作用,除非有人显式地将实例标记为“volatile”。如果没有,将其与null进行比较的检查可能会返回false,即使实例构造函数尚未完成运行。在Skeet先生的第三个示例中,他清楚地说明了这一点:“Java内存模型不能确保在将对新对象的引用分配给实例之前完成构造函数。Java内存模型在版本1.5中进行了重新设计,但在没有易失性变量的情况下(如C#),双重检查锁定仍然被破坏。” 然而,

可能重复:

Jon Skeet的优秀文章at和我读过的其他文章清楚地表明,双重检查锁定在C#和Java中都不起作用,除非有人显式地将实例标记为“volatile”。如果没有,将其与null进行比较的检查可能会返回false,即使实例构造函数尚未完成运行。在Skeet先生的第三个示例中,他清楚地说明了这一点:“Java内存模型不能确保在将对新对象的引用分配给实例之前完成构造函数。Java内存模型在版本1.5中进行了重新设计,但在没有易失性变量的情况下(如C#),双重检查锁定仍然被破坏。”

然而,大多数人都同意(包括Skeet先生,在他的文章的示例4和示例5中),使用静态初始化是获取线程安全单例实例的简单方法。他指出,“C#中的静态构造函数被指定为仅在创建类实例或引用静态成员时执行,并且每个AppDomain仅执行一次。”

这是有道理的,但似乎缺少的是保证只有在构造函数完成后才分配对新对象的引用——否则我们会遇到同样的问题,导致双重检查锁定失败,除非您将实例标记为volatile。当使用静态初始化来调用实例构造函数时(与从属性的get{}调用实例构造函数不同,就像我们使用双重检查锁定一样),是否可以保证构造函数将在任何其他线程获得对对象的引用之前完全完成


谢谢

是;声明中保证它只在每个AppDomain中执行一次

只有当它可以执行多次时才可能是不安全的;如前所述,它不能,所以一切都很好:)

构造函数将在任何其他线程获得对该对象的引用之前完全完成

每个
AppDomain
,静态初始值设定项将仅被调用一次(至少由系统调用),并以同步方式调用,同时考虑“beforefieldinit”。因此,假设您没有做任何奇怪的事情,在静态初始值设定项中指定的任何静态字段都应该可以;任何其他使用静态字段的尝试都应该被静态构造函数阻止

对新对象的引用仅在构造函数完成后分配

事情发生的时候就发生了。例如,任何静态字段初始值设定项都发生在您通常认为的构造函数之前。但是由于其他线程被阻塞,这不应该是一个问题

然而:

  • 如果静态初始值设定项本身将引用传递到外部(通过调用引用作为参数的方法(包括“arg0”),则所有赌注都将被取消
  • 如果您使用反射来调用静态构造函数(是的,您可以这样做),疯狂通常会随之而来

我认为这回答了我的问题,但有几个后续问题:-你说其他线程被阻塞-实例构造函数不是这样,对吗?否则双重检查锁定问题将不存在?-你能澄清你的第一个要点吗?例如,如果我有一个静态字典对象,在静态构造函数中对于类I“new”它,然后调用myDict.Add()无数次以添加一组条目,是否保证所有这些Add()都调用将在任何其他线程可以使用myDict之前完成?2:是;只要它发生在static.cctor中,其他线程就应该被阻止。wrt实例构造函数…2个线程如何在构造过程中与实例对话?我的示例不好。请参阅此处的第3个示例:。除非设置“实例”volatile,编译器可能会内联构造函数和名为“instance”的变量可以在构造对象之前获取引用。另一个线程可能会获取此实例,导致双重检查的第一次检查返回false,然后该线程可能最终使用未构造的实例。我正在尝试确定使用类型初始化的简单操作是否完全阻止此操作,或者类似操作,避免发生。