Thread-safe static variables without mutexing?

只谈情不闲聊 提交于 2020-01-01 08:28:20

问题


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* MyClass::BadMethod()
{
  static Dog dog("Lassie");
  return &dog;
}

My library generates C++ code for end-users to compile as part of their application. The code it generates needs to initialize static variables in a thread-safe cross-platform manner. I'd like to use boost::call_once to mutex the variable initialization but then end-users are exposed to the Boost dependency.

Is there a way for me to do this without forcing extra dependencies on end-users?


回答1:


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();
}



回答2:


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.




回答3:


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.




回答4:


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.




回答5:


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.



来源:https://stackoverflow.com/questions/1052168/thread-safe-static-variables-without-mutexing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!