0

I am writting a thread safe singleton class as follows. The following implementation ensures that only one instance of the class in created. My use case is that I am using this instance in a multi thread environment where each thread may call getInstance() and do some work using the instance. My question is how can I ensure that only one thread is using the instance at a particular time, so as to prevent race conditions that might occur if multiple threads are trying to use the single instance at same time.

class Singleton {
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
 public:
    static Singleton& getInstance() {
        static Singleton s;
        return s;
    }
};
danish sodhi
  • 1,793
  • 4
  • 21
  • 31
  • If Windows, this may help: https://learn.microsoft.com/en-us/windows/desktop/sync/one-time-initialization – Michael Chourdakis Jan 03 '19 at 21:12
  • My development environment is in Linux. Thanks for suggestion :) – danish sodhi Jan 03 '19 at 21:13
  • 1
    You'll need to make it's members thread safe or come up with a way where only on thread can call and have a reference to the singleton at a time. You could leverage a `shared_ptr` to do this checking its `use_count` to see if a thread already has an instance. – NathanOliver Jan 03 '19 at 21:15
  • 1
    @πάνταῥεῖ How does that dupe answer this question? The OP wants to make sure only one thread at a time has a reference to the object, not if the initialization is thread safe, which they know. – NathanOliver Jan 03 '19 at 21:19
  • 2
    A `std::mutex` is the simple way to synchronise threads. – Jesper Juhl Jan 03 '19 at 21:23
  • I am using c++11 – danish sodhi Jan 03 '19 at 21:33
  • Recommended read and expands on @bruno notes: [How is Meyers' implementation of a Singleton actually a Singleton](https://stackoverflow.com/q/17712001/6610379) – Phil Brubaker Jan 04 '19 at 07:51

2 Answers2

5

One thing you could do is to just make all it's members thread safe by locking a mutex.

class Singleton {
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    std::mutex my_mutex_member;
 public:
    static Singleton& getInstance() {
        static Singleton s;
        return s;
    }
    void my_singleton_cool_function()
    {
        std::lock_guard<std::mutex> lg(my_mutex_member);
        // cool code here
    }
};

In the above example lg will lock the mutex and at the end of the function, when lg gets destroyed the destructor will unlock the mutex. This means only one thread can run the function at the same time. This allows all the threads to have a reference to the singleton, and will only block if two or more threads try to do the same thing at the same time.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
2

My question is how can I ensure that only one thread is using the instance at a particular time.

As a general rule, you can't.

Nathan Oliver's answer works in the special case where the only way for other modules to "use the instance" is by calling it's methods. In that case, you can ensure that every one of those methods locks the same mutex.

But, if your singleton exposes any public data member, then all bets are off: You will not have any way to control how other modules "use" your object's public data members.


Beware! Even if you make all of the data members private, and make the singleton object really, truly "thread safe;" that still does not guarantee the thread safety of other code that might depend on some relationship between your singleton object and some other data.

Thread safety isn't really about ensuring that "only one thread uses the object at a time." Thread safety is about preserving invariant relationships. For example, if you have a doubly-linked ring data structure, then an important invariant is, p->next->prev must always be equal to p.

A thread that wants to splice a new element into the ring must temporarily break the invariant. "Thread safety" in that case means ensuring that no other thread will be able to see the temporarily broken state.

Building a program out of "thread safe" objects doesn't make the whole program "thread safe", because the higher level program can depend on important invariant relationships between the objects. And, even though the objects are individually threads safe, there is no way for them to be aware of the higher-level relationships that are meaningful to the program as a whole.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57