std::call_once, when should it be used?
Example: I use it for libcURL to retrieve http(s) data from websites. In libcURL, you have to do a one-time global initialization before you're able to use the library. Given that initialization is not thread-safe, but requesting data from websites is thread-safe, I use call_once
that calls my initialization only once, no matter in what thread and whether it's called concurrently.
Imagine a singleton instance with some giant data (for some reason):
class Singleton {
public: static Singleton& get();
...
private: static std::unique_ptr<SingletonDataBase> instance;
}
How can we insure that the get function, when called correctly creates the instance (which for whatever reason is really large and can't go in static memory space). How do we achieve this?
- Use a
mutex
? kind of ugly I guess. - Use
std::call_once
? Nicer, and firmly gives the intention of the code:
Singleton& Singleton::get() {
static std::once_flag flag;
std::call_once(flag, [&](){ instance.reset(new SingletonDataBase()); });
return instance.get_interface()
}
Whenever you need to call something exactly once, its nice to use call_once
.
The typical use is when you want to initialize a global piece of data on-demand in a situation of possible contention (multi-threading).
Suppose you have the struct
struct A{ A() {/*do some stuff*/} };
and you want an instance of it in global scope.
If you do as below, it gets initialized before main, so it is not on-demand.
A a_global;
If you do as below, then it is on demand but it is not thread safe.
A *a_singleton = NULL;
A *getA() {
if (!a_singleton)
a_singleton = new A();
return a_singleton;
}
call_once
solves these two problems. Of course you can use some combination of other synchronization primitives instead, but you would just end up re-implementing your own version of call_once
.