Thread-safe static variables without mutexing?

Gili picture Gili · Jun 27, 2009 · Viewed 22.7k times · Source

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?

Answer

Todd Gardner picture Todd Gardner · Jun 27, 2009

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