Singleton & Multi-threading

后端 未结 6 595
有刺的猬
有刺的猬 2021-01-05 17:36

I have the following class

class Singleton
{
  private:

    static Singleton *p_inst;
    Singleton();

  public:

    static Singleton * instance()
             


        
相关标签:
6条回答
  • 2021-01-05 18:00

    In multi-threading that clause

    if(!p_inst)
    {
        p_inst = new Singleton();
    }
    

    is actually 3 separate actions. You are getting the value of p_inst, setting the value of p_inst and writing the value of p_inst. So get-set-write means that you need to put a lock around p_inst otherwise you can have 2 threads which create a Singleton value that each thread uses.

    Here is how you can view the issue, assume that your Singleton has a mutable field val:

    thread A -> p_inst is NULL
        thread B -> p_inst is NULL
           thread A -> set to Singleton (1)
               thread B -> set to Singleton (2)
                  thread C -> p_inst is Singleton (2)
                      thread A -> set val to 4
                          thread B -> set val to 6
                             thread C -> get val (it's 6)
                                 thread A -> get val (it's 4!!)
    

    You see? There's 2 copies of a Singleton floating about, neither of which knows about the other. The third thread which checks on the Singleton is only going to see the last assignment. But with locking, you can prevent multiple assignment and these types of problems.

    0 讨论(0)
  • 2021-01-05 18:02

    You can eliminate all issues by simply allocating (any way you choose) such objects before multiple threads are started. This may not always be possible due to design constraints (using the singletons in statics, you NEED lazy allocation, etc.), but it is simple and gives you control of the creation sequence. Sometimes tracking down issues with regard to order and time of allocation of such objects is a hassle that you can easily avoid.

    P.S. - I know that this doesn't directly answer your question, but it may be a practical solution to a real problem without complexity.

    0 讨论(0)
  • 2021-01-05 18:14

    You will have to use a mutex and lock the pointer before assigning or reading it, making this a slow (and imo just plain terrible) design pattern.

    0 讨论(0)
  • 2021-01-05 18:17

    For multithreaded construction, use static variable in an instance() function. Initialization of static variables is automatically protected by the compiler. Any other operations require explicit locking. Use mutexes.

    class Singleton
    {
      private:
    
        Singleton();
    
      public:
    
        static Singleton * instance()
        {
          static Singleton inst;
          return &inst;
        }
    };
    
    0 讨论(0)
  • 2021-01-05 18:18

    I will be brief: it depends on your compiler.

    • If your compiler implements multi-threading synchronization for local static (ie static instances embedded in a method), then use it and be done with it.
    • If not, Herb Sutter proved it was impossible.

    Now, you have to realize that you may not need this.

    There are 2 ways to deal with this, that do not require any multithread awareness.

    1. Simply use a static instance instead of dynamically allocate it. Safe and simple. May cause issue with initialization order if you need to access it from another static variable
    2. Create the singleton instance BEFORE having more than one thread. The usual trick is to call it from main.

    Of course, the real question is: can't you just pass a reference to the object rather than creating a global variable ? It would make testing easier ;)

    0 讨论(0)
  • 2021-01-05 18:18

    You should ask yourself what you mean by thread safety.

    • Does your singleton actually need thread safety?

      If not, consider a thread-static approach

    • Do you want to guarantee that no two instances of the singleton ever get created?

      If not, your above solution is probably fine, without any locking: you've got a race condition on construction - but you don't care since eventually only one will survive - however, you may have a resource leak unless you're careful, which may or may not be significant. (This is essentially a cache).

    • Do you want to guarantee that eventually only one instance remains?

    • Do you care about locking costs?

      If not (which is quite common), you can just put a lock around it and be happy.

    A singleton is a pattern that can address various problems - but what flavor of thread-safety is required has little to do with the singleton pattern itself and everything to do with what you want it for.

    0 讨论(0)
提交回复
热议问题