3

When a thread safe singleton has to be implemented using C++11 the only correct implementation I know is the following:

// header
class Singleton final {
public:
  static Singleton& getInstance();

private:
  Singleton() = default;
  Singleton(Singleton const&) = delete;
  void operator=(Singleton const&) = delete;
};

// implementation:
Singleton& Singleton::getInstance() {
  static Singleton instance;
  return instance;
}

In his Book "C++ Concurrency in Action" A. Williams writes that since C++11 "the initialization is defined to happen on exactly one thread" and so this "can be used as an alternative to std::call_once" when a single global instance is required. I wounder when the destructor of the Singleton is called when defined as above.

The standard (ISO/IEC 14882:2011) defines as part of §3.6.3 e. g.

Destructors for initialized objects (that is, objects whose lifetime has begun) with static storage duration are called as a result of returning from main and as a result of calling std::exit.

and

Calling the function std::abort() declared in cstdlib terminates the program without executing any destructors and without calling the functions passed to std::atexit() or std::at_quick_exit().

So what happens first on an clean exit (returning from main)? Are all threads stopped before or after the destructors "for initialized objects with static storage duration are called"?

I know that it is a bad idea to use a singleton that is provided by a shared library (which might be unloaded before other parts that might use it). What happens when Singleton::getInstance() is called e. g. from other (detached) threads? Could that lead to undefined behavior or will all threads (detached or not) be terminated/joined before the destructors of static variables are called?

(To be clear: I think singleton is an anti-pattern, but when I have to use it I want to know what kind of bad things could happen.)

Sonic78
  • 680
  • 5
  • 19
  • I don't understand the question, sorry. You quoted the text that tells you when the destructor is called. If you want to know specifically about detached threads, then [this answer](https://stackoverflow.com/a/27796014/560648) may be of interest to you. – Lightness Races in Orbit Mar 22 '18 at 23:00
  • [Quoting](http://en.cppreference.com/w/cpp/language/storage_duration): "**static** storage duration. The storage for the object is allocated when the program begins and deallocated when the program ends. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration, plus those declared with `static` or `extern`." Also take a look at `thread_local`. – user4581301 Mar 22 '18 at 23:21
  • 1
    I believe static destruction happens in reverse order from construction. That should mean the singleton is created **before** any references bound to it. I *suspect* there is only a problem if someone takes its *address* and uses that rather than a reference. But I am not 100% sure so... – Galik Mar 22 '18 at 23:25
  • 1
    I don't think this is a duplicate exactly but the answer is possibly buried here https://stackoverflow.com/questions/1008019/c-singleton-design-pattern – Galik Mar 22 '18 at 23:27
  • Pretty sure the answer to "will all threads (detached or not) be terminated/joined before the destructors of static variables are called?" is No. The thread keeps running and Ooopsie. No more static variable. Mind you a non-detatched thread [terminates](http://en.cppreference.com/w/cpp/error/terminate) as soon as the destructor is called if it hasn't already been joined. – user4581301 Mar 22 '18 at 23:31
  • @user4581301 But that's always going to be bad news. All threads should terminate before you exit main. You may get away with it if you know they have no static dependencies and being abruptly killed is not an issue for them. – Galik Mar 22 '18 at 23:34
  • 1
    I think you can't call the `Singleton::getInstance` method outside the Singleton class because it is not static and you can't create the instance of the `Singleton` since you declared the constructor as private. You should make the `Singleton::getInstance` as static. – Mohit Mar 23 '18 at 02:52
  • @Mohit: shame on me ;-) - I added the static (without it is not a usable singleton). thanks – Sonic78 Mar 23 '18 at 07:39
  • @user4581301 if [this answer](https://stackoverflow.com/a/4667273/2194843) is correct all threads are stopped when returning from main and as a result of calling std::exit. ([A not joined and not detached std::thread will call std::terminate](https://stackoverflow.com/questions/27392743/c11-what-happens-if-you-dont-call-join-for-stdthread/27392989#27392989) -> different situation.) But I am **not sure** if that is really true! (I would be happy if the only to be avoided situation for the singleton would be not using detached threads.) – Sonic78 Mar 23 '18 at 09:16
  • You have known a not joined and not detached thread will call `std::terminate`, and joined thread is certainly safe. In addition, you can avoid detached thread, so what else do you want to know? – xskxzr Mar 23 '18 at 10:01
  • Be aware that this implementation is still not a thread-safe implementation of singleton with MS compilers before VS2015, a race condition is still possible, because threads have to write instance state to shared storage. – Swift - Friday Pie Mar 23 '18 at 14:08

2 Answers2

2

So what happens first on an clean exit (returning from main)? Are all threads stopped before or after the destructors "for initialized objects with static storage duration are called"?

There is no requirement for std::exit to stop any threads, neither is for exit or _Exit. Partly because abruptly terminating another thread may terminate it at a wrong moment and cause deadlocks in other threads.

The threads are terminated when C++ or C run-time terminates and passes the control flow back to the OS by invoking exit_group (on Linux):

This system call is equivalent to _exit(2) except that it terminates not only the calling thread, but all threads in the calling process's thread group. This system call does not return.

That means that the destructors of global objects run in parallel with other existing threads in your process. You must terminate all other threads explicitly and in cooperative fashion before calling std::exit or returning from main.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • So you can say: Singletons (e. g. that one above) can be safely used as part of a multi-threaded system (developed in C++11 with "portable" std::thread) when all threads are "joined" before returning from main. Using detached threads could lead to unexpected behavior. (?) – Sonic78 Mar 23 '18 at 11:57
  • @Sonic78 I would rather that using global objects while any other thread called `std::exit` leads to undefined behaviour. You can have other threads running as long as they do not access the objects that are being destroyed. – Maxim Egorushkin Mar 23 '18 at 12:01
0

The global static and singleton function static destructors are called in reverse order when the last thread exits user code, so there is no chance of multithreading issues. It is possible for the main thread to exit and leave other threads running. It is only when all those threads die that the program really shuts down.

Singletons are great to avoid the issue that there are no guarantees on the order statics are constructed, and if one static depends on the content of another during construction, then behaviour is undefined. With singletons your statics are effectively created on demand.

One issue you do have to be aware of is the phoenix singleton during shutdown. The singleton statics are destroyed in the reverse order to their finishing their construction, but another static/singleton(A) object that was constructed earlier, and didn't call on the singleton(B) during construction might call on the singleton(B) during its own(A) destruction, after the singleton(B) has been destructed.

There is no actual mechanism to cope with this, so std::string uses a reference count and does not rely on the singleton destructor.

Depending on the particular singleton, you might be able to leave the static data in a recognisable phoenix state, so it can either resurrect itself, or disable itself.

For example, a global mutex could be wrapped so that it actually does not lock after it has been phoenixed. There is only one thread, so who cares? A debug logger could temporarily reopen the log file in append mode if phoenixed, perhaps emitting a message to say it is being called too late. Note that these late created objects will never be auto-destructed.

Gem Taylor
  • 5,381
  • 1
  • 9
  • 27
  • The first paragraph is incorrect. The destructors of global objects are called by `std::exit`, which can be called by any thread, but normally it is the thread that returns from `main`. – Maxim Egorushkin Mar 23 '18 at 15:18
  • I don't have time currently to find the recent counterexample of someone debugging and finding eclipse terminated the debug run early. I don't know how they exited, but I know it is possible. – Gem Taylor Mar 23 '18 at 17:46
  • Here is a recent claim that main doesn't cause death if you have worker threads: They could be wrong: https://stackoverflow.com/questions/49457943/program-doesnt-stop-after-returning-0-from-main – Gem Taylor Mar 23 '18 at 20:46