Threads in the Gabi Software Library

Status

Threading is currently very experimental. There are no tests for thread-safety. To be frank, I'm not sure how to develop such tests.

Preconditions

The thread safety here presupposes that static initialization runs in a thread safe context, and that memory will be fully synchronized after static initialization. If initialization occurs before main is called, which is the case for statically linked modules in all compilers I am aware of, and no threads are created in static initializers, the conditions are met.

I'm less sure about what happens when dynamically linking is involved. Presumably, the runtime linker will run the initialization routines in its own thread, isolated from the rest of the program. Which still leaves two questions to be answered:

Singletons

Our thread safe singleton is implemented as follows:
Components:
The singleton contains three critical components, the static instance function, a static pointer to the single instance, and a static createInstance function.
Initialization:
The static pointer is initialized by the createInstance function, e.g.
    MySingleton* MySingleton::ourInstance = MySingleton::createInstance() ;
The goal here is to ensure that createInstance is called before static initialization has finished, and thus, before threading has begun. A critical invariant here is that this variable must not change its value once threading has been started.
createInstance
This function is not thread-safe, and should only be called before threading is active. It checks that the pointer is null, returning either the value of the pointer, or a new instance, e.g.:
    MySingleton*
    MySingleton::createInstance()
    {
        return ourInstance == NULL
            ?   new MySingleton()
            :   ourInstance ;
    }
instance
This is the only function visible at the user interface level. It checks if ourInstance is NULL, and calls createInstance if so, e.g.
    MySingleton&
    MySingleton::instance()
    {
        if ( ourInstance == NULL ) {
            ourInstance = createInstance() ;
        }
        return *ourInstance ;
    }
Two situations must be considered: when the function is called during static initialization, and later. In the first case, because of order of initialization issues, there is no guarantee as to the value of ourInstance. It could be null, and createInstance will be called. However, since threading has not yet started, there should be no problem. In the second case, because static initialization has finished, we know that createInstance has already been called at least once, and that the value of ourInstance is immutable and not null. Since the value is immutable, no synchronization is needed to ensure correct access to the variable, and since the value is not null, the non-thread-safe function createInstance will not be called.
Note too that this depends on the correct execution of zero initialization, before any dynamic initialization runs, so that createInstance and instance are guaranteed to see a null pointer in ourInstance if the pointer hasn't been (dynamically) initialized.

Dynamic objects

I'm not too sure about this with dynamically linked objects (shared objects in Posix, dynamicall linked libraries in Windows). Hopefully, all static initialization will take place in a context totally isolated from any threading that might already be active, so the code itself should work. The second question is synchronization. Are all threads (including those started before the dynamic object was loaded) guaranteed to see the correctly initialized values? A priori, I find it difficult to imagine that this is not the case, but Posix doesn't list dlopen in the list of functions which guarantee memory synchronization.