Initializing Shared Resources Once
Problem
You have a number of threads that are using a resource that must only be initialized once.
Solution
Either initialize the resource before the threads are started, or if you can't, use the call_once function defined in and the type once_flag. Example 12-5 shows how to use call_once.
Example 12-5. Initializing something once
#include #include #include // Some sort of connection class that should only be initialized once struct Conn { static void init( ) {++i_;} static boost::once_flag init_; static int i_; // ... }; int Conn::i_ = 0; boost::once_flag Conn::init_ = BOOST_ONCE_INIT; void worker( ) { boost::call_once(Conn::init, Conn::init_); // Do the real work... } Conn c; // You probably don't want to use a global, so see the // next Recipe int main( ) { boost::thread_group grp; for (int i = 0; i < 100; ++i) grp.create_thread(worker); grp.join_all( ); std::cout << c.i_ << ' '; // c.i_ = 1 }
Discussion
A shared resource has to be initialized somewhere, and you may want the first thread to use it to do the initializing. A variable of type once_flag (whose exact type is platform-dependent) and the call_once function can keep multiple threads from re-initializing the same object. You have to do two things.
First, initialize your once_flag variable to the macro BOOST_ONCE_INIT . This is a platform-dependent value. In Example 12-5, the class Conn represents some sort of connection (database, socket, hardware, etc.) that I only want initialized once even though multiple threads may try to initialize it. This sort of thing comes up often when you want to load a library dynamically, perhaps one specified in an application config file. The once_flag is a static class variable because I only want one initialization, no matter how many instances of the class there may be. So, I give the flag a starting value of BOOST_ONCE_INIT like this:
boost::once_flag Conn::initFlag_ = BOOST_ONCE_INIT;
Then, in my worker function, I invoke call_once, which synchronizes access to my init flag and, therefore, forbids concurrent initialization. I pass two arguments to call_once:
boost::call_once(Conn::init, Conn::initFlag_);
The first argument is the address of the function that will be doing the initialization. The second is the flag. This way, multiple threads can try to initialize the Conn class, but only the first will succeed.