Thread safe lazy construction of a singleton in C+

2019-01-07 05:01发布

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

  1. Lazily constructed in a thread safe manner (two threads might simultaneously be the first user of the singleton - it should still only be constructed once).
  2. Doesn't rely on static variables being constructed beforehand (so the singleton object is itself safe to use during the construction of static variables).

(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..)


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. 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.

9条回答
趁早两清
2楼-- · 2019-01-07 05:36

While this question has already been answered, I think there are some other points to mention:

  • If you want lazy-instantiation of the singleton while using a pointer to a dynamically allocated instance, you'll have to make sure you clean it up at the right point.
  • You could use Matt's solution, but you'd need to use a proper mutex/critical section for locking, and by checking "pObj == NULL" both before and after the lock. Of course, pObj would also have to be static ;) . A mutex would be unnecessarily heavy in this case, you'd be better going with a critical section.

But as already stated, you can't guarantee threadsafe lazy-initialisation without using at least one synchronisation primitive.

Edit: Yup Derek, you're right. My bad. :)

查看更多
可以哭但决不认输i
3楼-- · 2019-01-07 05:41

You can't do it without any static variables, however if you are willing to tolerate one, you can use Boost.Thread for this purpose. Read the "one-time initialisation" section for more info.

Then in your singleton accessor function, use boost::call_once to construct the object, and return it.

查看更多
SAY GOODBYE
4楼-- · 2019-01-07 05:49
  1. read on weak memory model. It can break double-checked locks and spinlocks. Intel is strong memory model (yet), so on Intel it's easier

  2. carefully use "volatile" to avoid caching of parts the object in registers, otherwise you'll have initialized the object pointer, but not the object itself, and the other thread will crash

  3. the order of static variables initialization versus shared code loading is sometimes not trivial. I've seen cases when the code to destruct an object was already unloaded, so the program crashed on exit

  4. such objects are hard to destroy properly

In general singletons are hard to do right and hard to debug. It's better to avoid them altogether.

查看更多
登录 后发表回答