27

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.

Bret Copeland
  • 22,640
  • 1
  • 25
  • 25
darune
  • 10,480
  • 2
  • 24
  • 62
  • I don't know of any case that wouldn't be better served by [possibly local-]static object constructor. – yuri kilochek Apr 03 '19 at 08:08
  • @yurikilochek What if you want it in the global scope, but not constructed before main? – Fantastic Mr Fox Apr 03 '19 at 08:17
  • @FantasticMrFox that's what I mean by possibly local. Put it in a function and it will be initialized when control flow first reaches it. – yuri kilochek Apr 03 '19 at 08:57
  • @yurikilochek why "better served"? Yes both can be used to do that, but I would suggest `std::call_once` is the "better" one here. – Caleth Apr 03 '19 at 10:34
  • @Caleth I believe it's cleaner and simpler, since constructors are intended for object initialization. It also prevents potential use-before-initiazation bugs. – yuri kilochek Apr 03 '19 at 12:32
  • @yurikilochek what constructor? the callable already exists, we just want to call it. Or do you mean "define a new class to call the callable, and have a static instance of it", see my answer – Caleth Apr 03 '19 at 12:48
  • It's a mechanism for [lazy initialization](https://en.wikipedia.org/wiki/Lazy_initialization). – Pete Becker Apr 03 '19 at 14:22
  • I'd imagine this is in contrast to something like ["magic statics"](https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables). Maybe the answer is as simple as you only have the function to call – Niall Apr 03 '19 at 20:34
  • 1
    @darune, I believe your accepted answer is incorrect - please consider unaccepting it. – einpoklum Nov 02 '20 at 09:13
  • @einpoklum Both yes and no. Its true you can also do this with statics, but it's not configurable like statics and doesn't need an extra struct. Thats a lot of extra code actually if you only need thread-safe global init. so that alone gives credence. – darune Nov 05 '20 at 09:27
  • 1
    @darune: It's true that you can do it both ways, but the accepted answer is incorrect in saying that static initialization is not thread-safe (and this is its emphasized point). So right now, we are telling people something misleading. – einpoklum Nov 05 '20 at 09:46
  • @yurikilochek What "potential use-before-initialization bugs"? Could you please explain that in more detail for me? – John Sep 05 '21 at 05:43
  • @einpoklum Any reference for static initialization is thread-safe? What about Static local variables? – John Sep 05 '21 at 05:52
  • @John: See [this answer](https://stackoverflow.com/a/8102145/1593077) by KerrekSB. – einpoklum Sep 05 '21 at 06:50

7 Answers7

30

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.

The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
  • 1
    It is not true that you need std::call_once for one-time global initialization. C++11 mandates that static-storage objects be safely initializable. See [this post](https://iamroman.org/blog/2017/04/cpp11-static-init/) for an example of how a compiler arranges for that to happen. No need for std::call_once for this. – einpoklum Nov 02 '20 at 09:13
  • 3
    @einpoklum `static` and `std::call_once` are not the same in this context. `std::call_one` has a state *that's controlled by the developer*. In my example, you may have many different places where the initialization must be called, but must be called once only by whoever wants to do the request first. Static will help you if your execution path is well-defined, which is not always the case, especially in things like GUI applications. – The Quantum Physicist Nov 03 '20 at 18:38
8

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.

Fabio
  • 2,105
  • 16
  • 26
  • If a_singleton doesn't need to be global wouldn't this work: `A *getA() { static A* a_singleton = new A(); return a_singleton; }` Is it because deleting a_singleton can't be done? I guess that only matters if the destructor of A isn't trivial.... – Jerry Jeremiah Jun 10 '20 at 01:35
  • 2
    @Fabio: I believe you are mistaken; that is, a local static is indeed initialized on demand, but the C++11 standard requires that this initializatin be thread-safe. See [this post](https://stackoverflow.com/a/8102145/1593077). – einpoklum Nov 02 '20 at 09:15
6

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?

  1. Use a mutex? kind of ugly I guess.
  2. 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.

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • While this is valid, it's probably bad for performance in the case of logging. You're adding one synchronizing atomic call for every log message. In my book, logging should be as low-profile as possible. It's the reason why async logging is popular. I personally use `static` to initialize the logger. The same one you used to initialize the flag. – The Quantum Physicist Apr 03 '19 at 10:11
  • Why wouldn't you just use a standard thread-safe function-local static instead? Far simpler. – Deduplicator Apr 03 '19 at 10:51
  • 1
    @TheQuantumPhysicist The bold text said `which for whatever reason is really large and can't go in static memory space` which admittedly is contrived for a logger example. The point was mainly to imagine a singleton which is very large. – Fantastic Mr Fox Apr 03 '19 at 13:31
  • @Deduplicator see above. – Fantastic Mr Fox Apr 03 '19 at 13:31
  • Hm. Generally, only stack-space is that limited. But whatever, there is probably at least one such oddball out there. – Deduplicator Apr 03 '19 at 13:49
  • Isn't this a rather exotic use case for a standard library member function? – einpoklum Nov 02 '20 at 09:24
6

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).

Ben
  • 9,184
  • 1
  • 43
  • 56
  • If using this pattern, if we want to allow the state to be reset, following https://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/ guidance on concurrency safety of `const` methods but not on non-`const`, I think we can add a `protected: void resetFoo() { m_flag.~once_flag(); new (&m_flag) std::once_flag{}; } to reset the flag in a concurrency-unsafe way. I think that makes calling `foo()` just as concurrency safe as manipulating an `int`. – Ben Sep 29 '21 at 14:01
1

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);
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • `foo_once` is an additional name too. Also, it is unlikely that you just have a callable that you want to call. Usually you want to wrap that in some error handling code, which you may as well put in the contractor. At that point there is not much difference in the amount of boilerplate. – yuri kilochek Apr 03 '19 at 14:42
  • @yurikilochek both alternatives introduce the name `foo_once`, as an object with no members. The first also introduces `CallFooOnce` You can put your error handling code around `std::call_once(foo_once, foo);` as if it were around `foo()`, or further away, and get to try again – Caleth Apr 03 '19 at 14:44
  • @yurikilochek both alternatives behave identically if `foo()` throws. The static initialisation deadlocks if it is re-entrant, I can't find anything specific about what `std::call_once` does in that situation, but at a guess it also deadlocks – Caleth Apr 03 '19 at 14:58
  • The point about class name is yours, though if that class is also local it's a minor issue. By error handling I meant that `foo` is a C function that returns some kind of error value and doesn't throw (otherwise this initialization should have been inside a constructor of a proper RAII capable class anyway). In that case you can't just pass `foo` to `std::call_once`, and have to wrap it in a function that inspects the error value and possibly converts it to exception. This wrapper function might as well be a constructor. – yuri kilochek Apr 03 '19 at 17:24
  • This is a sort of a homuculus answer. You call `do_thing()` when you want to have the thing done. The question is _when_ do you need to call something once ? ... and it's not for having a thread-safe singleton, because a static variable in a `get()` static member is thread-safe. – einpoklum Nov 02 '20 at 09:22
  • @einpoklum "Since this can be achieved by other means": `call_once` is a good name. You use it over the alternatives because it does exactly one thing, so you don't have to think about what *it* is doing. – Caleth Sep 13 '21 at 08:35
0

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.

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
-1

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;
  } 

};