lundi 17 janvier 2022

What is a proper way to make my Singleton thread safe

I'm working with C++11 and I'm trying to implement a singleton which works at multi-threading project.

template <typename T>
class Singleton
{
    public:
        Singleton(const Singleton&&) = delete;
        Singleton(Singleton&&) = delete;
        Singleton& operator=(const Singleton&) = delete;
        Singleton& operator=(Singleton&&) = delete;

        static T* getInstance()
        {
            static Protector protector {instance};
            return instance;
        }

        template<typename... Args>
        static void createInstance(Args&&... args) {
            static T t(std::forward<Args>(args)...);
            instance = &t;
        }

    private:
        Singleton() = default;
        ~Singleton() = default;

        static T* instance;

        struct Protector {
            Protector(T* p) {
                if (p == nullptr) {
                    assert("not-init");
                }
            }
        };
};

template<typename T>
T* Singleton<T>::instance = nullptr;

class Test
{
    friend class Singleton<Test>;
    private:
        Test(int aa): a{aa} {};
        ~Test(){};                    
        int a;      
    public:
        void print(void) {std::cout << "hello " << a << std::endl;}
};

int main(void)
{
    Singleton<Test>::createInstance(1);
    Singleton<Test>::getInstance()->print();

    return 0;
}

I've known that the initialization of static variable is thread safe in C++11 so I think this shouldn't cause any problem (https://stackoverflow.com/a/1661564/3305546).

The inner class named Protector is used to make sure that createInstance() has been called before calling getInstance(). I think this should be OK too.

But after reading this link, it seems that instance = &t; in the funciton createInstance() could cause race condition if the function is called in multi threads? If so, what is the proper way to solve this issue? Replace static T* instance with std::atomic<T*> instance?

Aucun commentaire:

Enregistrer un commentaire