线程安全lazy构造一个单例在C + + [英] Thread safe lazy construction of a singleton in C++

查看:170
本文介绍了线程安全lazy构造一个单例在C + +的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一种方法可以在C ++中实现一个单例对象,它是:

Is there a way to implement a singleton object in C++ that is:


  1. 以线程安全方式同时成为单例的第一个用户 - 它应该只被构造一次)。

  2. 不依赖于事先构建的静态变量(因此单例对象本身可以安全使用静态变量的构造)。

(我不知道我的C ++足够好,静态变量在任何代码执行之前被初始化(即,甚至在静态构造函数被执行之前,它们的值可能已经在程序映像中被初始化)?如果是这样 - 可能被利用来实现单例互斥)

(I don't know my C++ well enough, but is it the case that integral and constant static variables are initialized before any code is executed (ie, even before static constructors are executed - their values may already be "initialized" in the program image)? If so - perhaps this can be exploited to implement a singleton mutex - which can in turn be used to guard the creation of the real singleton..)

很好,似乎我有几个好的答案现在(耻辱我不能标记2或3为答案)。看起来有两个广泛的解决方案:

Excellent, it seems that I have a couple of good answers now (shame I can't mark 2 or 3 as being the answer). There appears to be two broad solutions:


  1. 使用静态初始化(而不是动态初始化)POD静态变量,互斥与使用内置的原子指令。这是我在我的问题中暗示的解决方案类型,我相信我已经知道了。

  2. 使用一些其他库函数,如pthread_once 提高: :call_once 。这些我当然不知道 - 非常感谢所发布的答案。

  1. Use static initialisation (as opposed to dynamic initialisation) of a POD static variable, and implementing my own mutex with that using the builtin atomic instructions. This was the type of solution I was hinting at in my question, and I believe I knew already.
  2. Use some other library function like pthread_once or boost::call_once. These I certainly didn't know about - and am very grateful for the answers posted.


推荐答案

基本上,你要求同步创建单例,而不使用任何同步(以前构造的变量)。一般来说,不,这是不可能的。你需要一些可用于同步的东西。

Basically, you're asking for synchronized creation of a singleton, without using any synchronization (previously-constructed variables). In general, no, this is not possible. You need something available for synchronization.

对于你的其他问题,是的,可以静态初始化的静态变量(即不需要运行时代码)保证在执行其他代码之前被初始化。

As for your other question, yes, static variables which can be statically initialized (i.e. no runtime code necessary) are guaranteed to be initialized before other code is executed. This makes it possible to use a statically-initialized mutex to synchronize creation of the singleton.

从C ++标准的2003年修订版本:

From the 2003 revision of the C++ standard:

具有静态存储持续时间的对象3.7.1)在任何其他初始化之前应进行零初始化(8.5)。具有常数表达式的零初始化和初始化统称为静态初始化;所有其他初始化是动态初始化。使用常量表达式(5.19)初始化的静态存储持续时间的POD类型(3.9)的对象应在任何动态初始化发生之前初始化。

Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.

如果您知道,在同一翻译单元的命名空间范围中定义静态存储持续时间并动态初始化的对象应按照它们在翻译单元中出现的顺序进行初始化。 ,您将在其他静态对象的初始化期间使用此单例,我认为您会发现同步是一个非问题。据我所知,所有主要编译器在单个线程中初始化静态对象,因此在静态初始化期间线程安全。您可以将单例指针声明为NULL,然后在使用之前检查其是否已初始化。

If you know that you will be using this singleton during the initialization of other static objects, I think you'll find that synchronization is a non-issue. To the best of my knowledge, all major compilers initialize static objects in a single thread, so thread-safety during static initialization. You can declare your singleton pointer to be NULL, and then check to see if it's been initialized before you use it.

但是,这假设您知道这个单例在静态初始化期间。这也不是标准保证的,所以如果你想完全安全,使用静态初始化的互斥。

However, this assumes that you know that you'll use this singleton during static initialization. This is also not guaranteed by the standard, so if you want to be completely safe, use a statically-initialized mutex.

编辑:Chris的建议使用原子比较和交换肯定会工作。如果可移植性不是一个问题(并且创建额外的临时单例不是问题),那么它是一个略低的开销解决方案。

Chris's suggestion to use an atomic compare-and-swap would certainly work. If portability is not an issue (and creating additional temporary singletons is not a problem), then it is a slightly lower overhead solution.

这篇关于线程安全lazy构造一个单例在C + +的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆