Hi Glen, It solves other issues, not just the multi-threading problem, which makes it applicable even for c++11 compilers. Performance wise it does not include multi-thread primitives which makes it I would assume many times faster. Arguable it is even faster than the pattern used in path_locale, because it does not check if the object is initialized for every call. It is not in GitHub yet, I will let you know when I publish it. If I ignore some of the smarts the main concept is very simple: The access to the global object can be raw, shared or other pointer, say typedef boost::shared_ptr<GlobalLogger> GlobalLoggerSPtr; extern GlobalLoggerSPtr gLogger; then the initialization of the pointer is, say GlobalLoggerSPtr gLogger = GlobalObjectManager::registerPointer(orderIndex, gLogger, initFn, uninitFn); registerPointer method does NOT call the initFn, but instead returns something arbitrary (say null pointer), but as side effect stores the address of the global object pointer in a container. then you start your main (something that I hope I could find a way to avoid) with constructing a GlobalObjectManager object. int main(int argc, char **argv) { GlobalObjectManager gom(argc, argv); ... } The constructor of GlobalObjectManager initialize all the registered objects pointers in the appropriate order. The destructor uninitializes in reverse order. For the rest of the code it seems like the initialization was part of the crt initialization - but we had control over the order. In case of one global object depends on another all you need to do is to make sure that their orderIndexes are correctly offseted. My implementation have some smarts to help for defining the order relatively easy, and offers a set of helper methods and default initializers and uninitializes that allow to do the most of the most common cases relatively simple - for example the code for my logger looks: GlobalLoggerSPtr gLogger = GlobalObjectManager::sharedPointer(gLogger); Now when I need access to the logger object all I need to do is: gLogger->... Note that the consumer library does not need to know how this pointer is initilized (no dependencies to the GlobalObjectManager). Also, if my logger is in a static library that I am linking, but I do not use it - the gLogger pointer is not going to be initialized, this will result its initialization to not be added to the GlobalObjectManager and as result all the code required for the logger will not be added to the binary. If I would like to replace the logger with a mock, all I need to do is - static void initilizeGlobalLoggerMock() { gLogger = boost::make_shared<GlobalLoggerMock>(); } GlobalObjectManager::genericRegister(orderIndex - 1, &initilizeGlobalLoggerMock, NULL); Note that I am subtracting one from the orderIndex - this will guarantee that this initialization will be called before the original one. Now because GlobalObjectManager::sharedPointer does not replace the pointer unless it is NULL, when I run the code (in test environment) the same code that uses the pointer will be execute against the mock object without any change. Please let me know what do you think? Thanks, George On Sat, Jun 7, 2014 at 4:58 PM, Glen Fernandes <glen.fernandes@gmail.com> wrote:
Hi George,
On Sat, Jun 7, 2014 at 3:28 PM, George Georgiev wrote:
I have code that deals with problems related to initialization of global objects (singletons). 1. Multi-threading - problems occurring in some singleton patterns based on the fact that local for a function or method static variables are not initialized in a thread safe manner
Did you mean specifically for C++03 / non-C++11 compilers? With C++11, initialization of function-local statics is guaranteed to be thread-safe.
For those compilers that do not implement that C++11 requirement (like VC12), how does your solution for thread-safe singleton initialization compare (performance-wise) to, say,
http://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html#boo... or other alternatives?
In any case, I'm curious to see your solution. Is it on GitHub?
[ Side note: Instead of boost::shared_ptr<T>(new T(...)) always prefer boost::make_shared<T>(...). For better performance (one allocation instead of two) and exception-safety. Granted, this is a test snippet, but I also noticed it in Compil. :-) ]
Glen
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost