我有以下示例C ++代码:
class Factory
{
public:
static Factory& createInstance()
{
static Factory fac;
return fac;
}
private:
Factory()
{
//Does something non-trivial
}
};
我们假设createInstance
同时被两个线程调用。那么生成的对象是否会正确创建?当第一个线程在createInstance
的构造函数中时第二个线程进入Factory
调用会发生什么?
答案 0 :(得分:6)
C ++ 11及更高版本:本地静态创建是线程安全的。
该标准保证:
通常采用双重检查实现:
C ++ 03和C ++ 98:标准没有线程。
就标准而言,没有线程,因此标准中没有关于跨线程同步的规定。
然而,有些编译器实现了 more 而不是标准的任务,无论是以扩展的形式还是通过提供更强的保证,所以请查看您感兴趣的编译器。如果它们是高质量的编译器,很有可能他们会保证。
最后,它可能没有必要是线程安全的。如果在创建任何线程之前调用此方法,那么您可以确保在真正的多线程发挥作用之前将其正确初始化,并且您可以巧妙地解决问题。
答案 1 :(得分:2)
查看this page,我会说这不是线程安全的,因为构造函数可能在最终分配变量之前被多次调用。可能需要InterlockedCompareExchange()
,您可以在其中创建变量的本地副本,然后通过互锁函数以原子方式将指针指定给静态字段,如果静态变量为null。
答案 2 :(得分:0)
当然它是线程安全的!除非你是一个完整的疯子并且从静态对象的构造函数中生成线程,否则在调用main()之后你将没有任何线程,并且createInstance方法只是返回对已经构造的对象的引用,这是不可能的失败。 ISO C ++保证在调用main()之后第一次使用之前构造对象:不能保证在调用main之前,但必须在第一次使用之前,因此所有系统都将在执行之前执行初始化调用main()。当然,ISO C ++没有在线程或动态加载的情况下定义行为,但是主机级机器的所有编译器都提供了这种支持,并且会尽可能保留为单线程静态链接代码指定的语义。
答案 3 :(得分:0)
实例化(第一次调用)本身是threadsafe。
但是,一般来说,后续访问不会。例如,假设在实例化之后,一个线程调用一个可变的Factory方法,而另一个线程在Factory中调用一些访问器方法,那么你将遇到麻烦。
例如,如果您的工厂保留了创建的实例数量的计数,那么在没有围绕该变量的某种互斥体的情况下,您将遇到麻烦。
但是,如果Factory真的是一个没有状态的类(没有成员变量),那么你就可以了。