0

The question may be wrong in wording but the idea is simple. The order of initialisation of global objects in different translation units is not guarantied. If an application consists of two translation units - can compiler potentially generate initialisation code that will start two threads to create global objects in those translation units? This question is similar to this or this but I think the answers don't match the questions. I will rephrase the question - if a program has several global objects - will their constructors always be called from the same thread (considering that user code doesn't start any threads before main)?

To make this question more practical - consider a case when several global objects are scattered over several translation units and each of them increments single global counter in constructor. If there is no guarantee that they are executed in single thread then access to the counter must be synchronised. For me it's definitely overkill.

UPDATE:

It looks like concurrent initialisation of globals is possible - see n2660 paper (second case)

UPDATE:

I've implemented singleton using singleton_registry. The idea is that declaration using SomeSingleton = singleton<SomeClass>; registers SomeClass for further initialisation in singleton_registry and real singleton initialisation (with all inter-dependencies) happens at the beginning of main function (before I've started any other threads) by singleton_registry (which is created on stack). In this case I don't need to use DLCP. It also allows me to prepare application configuration and disseminate it over all singletons uniformly. Another important use case is usage of singletons with TDD. Normally it's a pain to use singletons in unit tests, but with singleton_registry I can recreate application global objects for each test case.

In fact this is just a development of an idea that all singletons must be initialised at the beginning of function main. Normally it means that singleton user has to write custom initialisation function which handles all dependencies and prepare proper initialisation parameters (this is what I want to avoid).

Implementation looks good except the fact that I may have potential race conditions during singletons registration.

Community
  • 1
  • 1
AlexT
  • 1,413
  • 11
  • 11
  • But C++ does guarantee globals will be destructed in the reverse order they are constructed. – brian beuning Mar 08 '14 at 17:18
  • @brianbeuning I agree - "natural" way of initialising and destroying global objects would be in the same thread as function main but last Stroustrup book made me think that it's just one of the possibilities – AlexT Mar 08 '14 at 17:25
  • 1
    I don't think there's anything that prohibits concurrent initialization of multiple TUs, as long as each initialization finishes before any function in the TU is called. I'm also not aware of any compilers that produce such code, though. – Kerrek SB Mar 08 '14 at 17:29
  • AFAIK, no compiler currently uses threads to perform initialization prior to `main()`, everything is done in the main thread one TU at a time. – Remy Lebeau Mar 08 '14 at 17:33
  • @AlexT What ever random order the globals are constructed in, to be C++ compliant, they must be destroyed in the reverse random order. – brian beuning Mar 08 '14 at 17:33
  • @brian The problem is, doesn't that make it inherently a sequential process? If not you'd have to specify how to order them: Say you sequentially start k threads to initialize k objects - is the "first" one the first one who started working on an object or the first that's finished (presumably according to some queue)? Considering that initialization of globals in C++ is already more than unnecessarily complicated to begin with, that'd really make it nigh impossible to write correct code imo. – Voo Mar 08 '14 at 17:45
  • What problem are you trying to solve? Initialization happens once, so it's basically irrelevant whether it takes a microsecond longer or not. On the other hand, concurrent initialization is a recipe for desaster... – Damon Mar 08 '14 at 20:24
  • @Damon I've added some details regarding singleton_registry – AlexT Mar 09 '14 at 03:23

1 Answers1

1

Several projects ago, using vxWorks and C++, a team mate used a non-thread safe pattern from the book (are any of those patterns thread safe?):

  • 10% of system starts failed.

Lesson 1: if you don't explicitly control the when of a CTOR of a global object, it can change from build to build. (and we found no way to control it.)

Lesson 2: Controlling the when of CTOR is probably the easiest solution to lesson 1 (should it become a problem).

In my experience, if you gotta have Global objects (and it seems many would discourage it), consider limiting these globals to pointers initialized to 0:

GlobalObject* globalobject = nullptr;

And only the thread assigned to initialize it will do so. The other threads/tasks can spin wait for access.

2785528
  • 5,438
  • 2
  • 18
  • 20
  • I've added some details on the task that I'm trying to solve. And yes you are right - global constructors should be invoked at the beginning of main function. – AlexT Mar 09 '14 at 03:26
  • @AlexT - Note: The pattern that broke my system start up was Singleton. – 2785528 Mar 13 '14 at 00:25