Thread-safe static variables without mutexing?

前端 未结 5 1085
无人及你
无人及你 2021-02-19 10:32

I remember reading that static variables declared inside methods is not thread-safe. (See What about the Meyer\'s singleton? as mentioned by Todd Gardner)

Dog* M         


        
相关标签:
5条回答
  • 2021-02-19 10:58

    AFAIK, the only time this has been done safely and without mutexes or prior initialisation of global instances is in Matthew Wilson's Imperfect C++, which discusses how to do this using a "spin mutex". I'm not near to my copy of it, so can't tell you any more precisely at this time.

    IIRC, there are some examples of the use of this inside the STLSoft libraries, though I can't remember which components at this time.

    0 讨论(0)
  • 2021-02-19 11:03

    The only way I know of to guarantee you won't have threading issues with non-protected resources like your "static Dog" is to make it a requirement that they're all instantiated before any threads are created.

    This could be as simple as just documenting that they have to call a MyInit() function in the main thread before doing anything else. Then you construct MyInit() to instantiate and destroy one object of each type that contains one of those statics.

    The only other alternative is to put another restriction on how they can use your generated code (use Boost, Win32 threads, etc). Either of those solutions are acceptable in my opinion - it's okay to generate rules that they must follow.

    If they don't follow the rules as set out by your documentation, then all bets are off. The rule that they must call an initialization function or be dependent on Boost is not unreasonable to me.

    0 讨论(0)
  • 2021-02-19 11:04

    You are correct that static initialization like that isn't thread safe (here is an article discussing what the compiler will turn it into)

    At the moment, there's no standard, thread safe, portable way to initialize static singletons. Double checked locking can be used, but you need potentially non-portable threading libraries (see a discussion here).

    Here's a few options if thread safety is a must:

    1. Don't be Lazy (loaded): Initialize during static initialization. It could be a problem if another static calls this function in it's constructor, since the order of static initialization is undefined(see here).
    2. Use boost (as you said) or Loki
    3. Roll your own singleton on your supported platforms (should probably be avoided unless you are a threading expert)
    4. Lock a mutex everytime you need access. This could be very slow.

    Example for 1:

    // in a cpp:
    namespace {
        Dog dog("Lassie");
    }
    
    Dog* MyClass::BadMethod()
    {
      return &dog;
    }
    

    Example for 4:

    Dog* MyClass::BadMethod()
    {
      static scoped_ptr<Dog> pdog;
      {
         Lock l(Mutex);
         if(!pdog.get())
           pdog.reset(new Dog("Lassie"));
      }
      return pdog.get();
    }
    
    0 讨论(0)
  • 2021-02-19 11:10

    Not sure whether this is what you mean or not, but you can remove the boost dependency on POSIX systems by calling pthread_once instead. I guess you'd have to do something different on Windows, but avoiding that is exactly why boost has a thread library in the first place, and why people pay the price of depending on it.

    Doing anything "thread-safely" is inherently bound up with your threads implementation. You have to depend on something, even if it's only the platform-dependent memory model. It is simply not possible in pure C++03 to assume anything at all about threads, which are outside the scope of the language.

    0 讨论(0)
  • 2021-02-19 11:22

    One way you could do it that does not require a mutex for thread safety is to make the singleton a file static, rather than function static:

    static Dog dog("Lassie");
    Dog* MyClass::BadMethod()
    {
      return &dog;
    }
    

    The Dog instance will be initialised before the main thread runs. File static variables have a famous issue with the initialisation order, but as long as the Dog does not rely on any other statics defined in another translation unit, this should not be of concern.

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