Skip to main content
gamedev.net
🔒 Locked

multi-threaded singleton

Started by psykr Jan 7, 2007 at 8:18 AM 4 replies 2.9k views
Original Post
psykr
psykr
I am starting to work on thread-safety in my program, and I would like to have someone check over my work to make sure I am understanding it right. I am compiling on MSVC 2005 (and will cross-compile on GCC, so I want to make sure the code works). I use an object called nullptr instead of 0, except in InterlockedExchangePointer it gives a compiler error because that takes a LONG.
    template < typename T >
    class PhoenixSingletonHolder {
    public:
        typename typedef T ObjectType;
    private:
        static void MakeInstance() {
        #ifdef PSYKR_WIN32
            // create a new object, and slip it in the back
            T* NewInstancePtr = new T();
            // if the exchange failed, we already have an instance
            if( nullptr != InterlockedCompareExchangePointer( &InstancePtr, NewInstancePtr, nullptr ) )
                delete NewInstancePtr;
            // otherwise, we created a new object so schedule its destruction
            else std::atexit( &DestroySingleton );
        #else
            T* NewInstancePtr = new T();
            if( nullptr != InstancePtr )
                delete NewInstancePtr;
            else { // if( nullptr == InstancePtr )
                InstancePtr = NewInstancePtr;
                std::atexit( &DestroySingleton );
            }
        #endif //!PSYKR_WIN32
        }
        static void DestroySingleton() {
        #ifdef PSYKR_WIN32
            // this will either delete InstancePtr, or a nullptr (which is okay)
            delete( InterlockedExchangePointer( InstancePtr, 0 ) );
        #else
            delete InstancePtr;
            InstancePtr = nullptr;
        #endif //!PSYKR_WIN32
        }
    public:
        // this is what's really returned by Singleton<T>::Instance()
        static T& Instance() {
            if( nullptr == InstancePtr )
                MakeInstance();
            return *InstancePtr;
        }
    private:
        static T* volatile InstancePtr;
    };
Could someone also clarify the thread-safety of atexit() in this case? Is it acceptable to delete InstancePtr from another thread than the one that allocated it? I am going to be focusing on VC8 and GCC (MinGW) 3.4.2, although I intend to port it to another platform.
dmail
dmail
There is only one method that I know of to make the singleton pattern [edit] guaranteed (without locking with a mutex on every call to instance)[/edit]thread safe and this requires the use of memory barriers. Here is a paper by Scott Meyers and Andrei Alexandrescu explaining the problems. Check out loki source which has an example if I remember correctly.

[Edited by - dmail on January 7, 2007 12:41:56 PM]
paulecoyote
paulecoyote
loki source is good, I only found about that after I wrote this article many moons ago

http://www.codeproject.com/cpp/pdesingletontemplatenomfc.asp
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
psykr
psykr
My code is loosely based on the Loki singleton, except I am just providing an implementation of the phoenix singleton because I don't think I will use any other kind. However, I am trying to implement a lock-free version because the singleton only needs to be thread-safe during creation/destruction, which I don't feel justifies the overhead of a lock.

I don't know if memory barriers are put up around the Interlocked* calls, but the documentation says they are atomic operations so it should be fine.

Right now, I will only use this singleton to access a global logging class, which I think is a fine solution. The whole engine is also for learning purposes, and I wanted to learn about lock-free algorithms so I thought that a singleton would be a pretty easy place to start.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.