Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-safe static variables without mutexing?

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?

like image 466
Gili Avatar asked Jun 27 '09 05:06

Gili


People also ask

Are static function variables thread safe?

So yes, you're safe.

Can static variables be shared between threads?

Static variables are indeed shared between threads, but the changes made in one thread may not be visible to another thread immediately, making it seem like there are two copies of the variable.


1 Answers

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();
}
like image 95
Todd Gardner Avatar answered Nov 21 '22 17:11

Todd Gardner