liveBook · Manning

Std::once_flag

As explained in C++ Concurrency in Action, Second Edition

`std::once_flag` is a noncopyable C++ standard library type whose instances coordinate one-time execution with `std::call_once`.

`std::once_flag` holds synchronization data for one initialization; use a separate flag for each. Pass it and an initialization callable to `std::call_once`. When that call returns, initialization is complete in a properly synchronized fashion, so callers can use the object. This avoids unsafe pointer checks that can cause a data race. Compared with an explicit mutex, this approach typically has lower overhead, especially after initialization. section 3.3.1

std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;                       #1
void init_resource()
{
    resource_ptr.reset(new some_resource);
}
void foo()
{
    std::call_once(resource_flag,init_resource);    #2
    resource_ptr->do_something();
}

A flag and callable initialize a shared resource once before it is used. section 3.3.1

Listing 3.12. Thread-safe lazy initialization of a class member using std::call_once
class X
{
private:
    connection_info connection_details;
    connection_handle connection;
    std::once_flag connection_init_flag;
    void open_connection()
    {
        connection=connection_manager.open(connection_details);
    }
public:
    X(connection_info const& connection_details_):
        connection_details(connection_details_)
    {}
    void send_data(data_packet const& data)                             #1
    {
        std::call_once(connection_init_flag,&X::open_connection,this);  #2
        connection.send_data(data);
    }
    data_packet receive_data()                                          #3
    {
        std::call_once(connection_init_flag,&X::open_connection,this);  #2
        return connection.receive_data();
    }
};


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":14,\"ch\":72},{\"line\":14,\"ch\":74}],[{\"line\":16,\"ch\":72},{\"line\":16,\"ch\":74}],[{\"line\":21,\"ch\":72},{\"line\":21,\"ch\":74}],[{\"line\":19,\"ch\":72},{\"line\":19,\"ch\":74}],[{\"line\":16,\"ch\":72},{\"line\":16,\"ch\":74}],[{\"line\":21,\"ch\":72},{\"line\":21,\"ch\":74}]]"}
!@%STYLE%@!

A class member flag lets either send_data or receive_data trigger connection initialization. section 3.3.1

How C++ Concurrency in Action, Second Edition covers it

How deep it goes
Explains per-flag coordination, synchronized completion, callable arguments, and namespace-scope or class-member use.
Examples
Shows shared-resource initialization and a class connection first opened by send_data or receive_data.
What you can do after
Apply std::call_once with a flag and callable to initialize shared state before use.
How it connects
Relates std::call_once to mutexes, lazy initialization, shared pointers, and data races.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of C++ Concurrency in Action, Second Edition. The section links point to the parts of the book it draws on.