Protecting Data During Initialization
If your data only needs protecting during its initialization, using a mutex is not the answer. Doing so only leads to unnecessary synchronization after initialization is complete. The C++0x standard provides several ways of dealing with this.
First, suppose your constructor is declared with the new constexpr keyword and satisfies the requirements for constant initialization. In this case, an object of static storage duration, initialized with that constructor, is guaranteed to be initialized before any code is run as part of the static initialization phase. This is the option chosen for std::mutex, because it eliminates the possibility of race conditions with initialization of mutexes at a global scope:
my_class x; // static initialization with constexpr constructor
my_class y(42+foo()); // dynamic initialization
y.do_stuff(); // is y initialized?
Your second option is to use a static variable at block scope. In C++0x, initialization of block scope static variables happens the first time the function is called. If a second thread should call the function before the initialization is complete, then that second thread has to wait:
static my_class z(42+foo()); // initialization is thread-safe
If neither options apply (perhaps because the object is dynamically allocated), then it's best to use std::call_once
. As the name suggests, when std::call_once is used in conjunction with a specific instance of type std::once_flag
, the specified function is called exactly once:
Just as with the std::thread
can take function objects instead of functions, and can pass arguments to the function. Again, copying is the default, and you have to use std::ref
if you want a reference.