Reputation: 11000
The std::call_once
function, introduced in C++11, ensures a callable is called exactly one time, in a thread safe manner.
Since this can be achieved by other means - when should std::call_once
be used? What type of problems is it intended to address?
Please provide examples.
Upvotes: 32
Views: 24973
Reputation: 13689
Other answers already mentioned that call_once
effect may be achieved with magic static, or with mutex
usage.
I want to focus on performance and corner case handling.
Using mutex
will be slower than call_once
on fast path (when the target function is already called). That's because mutex
acquisition/release will be atomic RMWs, whereas call_once
queries are just reads. You can fix mutex
performance by implementing double-check lock, but this will complicate the program.
Using call_once
is also safer than mutex, if the target function is first attempted to be called only on program exit. mutex
isn't necessarily trivially destructible, so a global mutex may be destroyed by the time the target is to be called.
Magic static is also likely to be fast on fast path by making only reads to query if the object is already initialized. The performance of magic static vs call_once
may depend on implementation, but generally magic static has more opportunity for the optimization, as it doesn't have to expose the state in a variable and has to be implemented by the compiler rather than only in the library.
MSVC specific: magic statics employ thread-local storage. This is more optimal than call_once
. But magic static support can be turned off by /Zc:threadSafeInit-. The ability to turn it off is due to some thread-local storage disadvantages. call_once
cannot be turned off. Before Visual Studio 2015, call_once
wasn't implemented well, and magic statics weren't implemented at all, so it was hard to get one-time initialization without 3rd party libs.
Upvotes: 0
Reputation: 9713
Caching and lazy evaluation. Suppose an immutable class has a cheap-to-store but expensive-to-compute property, double foo() const;
. Rather than compute it on demand or compute it up front, you could do
private:
mutable std::once_flag m_flag;
mutable double m_foo;
double doCalcFoo() const; // Expensive!
public:
double foo() const {
std::call_once(m_flag, [this] { m_foo = doCalcFoo(); });
return m_foo;
}
While you could do
private:
mutable std::optional<double> m_foo;
mutable std::mutex m_fooMutex;
double doCalcFoo() const; // Expensive!
public:
double foo() const {
std::lock_guard lock{m_fooMutex};
if (!m_foo) {
m_foo = doCalcFoo();
}
return *m_foo;
}
that's more bytes (40 + 16 = 56 bytes versus 4 + 8 + padding = 16 on Clang), less performance-optimal, and violates Parent's Better-Code goal of "No Raw Synchronization Primitives": (https://sean-parent.stlab.cc/presentations/2016-08-08-concurrency/2016-08-08-concurrency.pdf slide 6 through 11).
Upvotes: 6
Reputation: 41
std::call_once()
can be used for Lazy Evaluation, in the way that the callable object passed to it will be executed only one time even if many threads execute it. See the next example, where the method getInstance()
may be called many times and by many threads, however the instance is created only one time and at the moment of needing it (call getInstance() for the first time).
#include <mutex>
class Singleton {
static Singleton *instance;
static std::once_flag inited;
Singleton() {...} //private
public:
static Singleton *getInstance() {
std::call_once( inited, []() {
instance=new Singleton();
});
return instance;
}
};
Upvotes: -1
Reputation: 63019
When should it be used ?
When you want to call something once. It is concise and clear as to what it is doing.
The alternative
struct CallFooOnce {
CallFooOnce() {
foo();
}
};
static CallFooOnce foo_once;
has much more boilerplate, and introduces an additional name, over
static std::once_flag foo_once;
std::call_once(foo_once, foo);
Upvotes: 1
Reputation: 2287
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
.
Upvotes: 9
Reputation: 33904
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?
mutex
? kind of ugly I guess.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
.
Upvotes: 6
Reputation: 26326
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.
Upvotes: 34