Search code examples
c++mutexc++20atomicstdatomic

How to guard the initialization of data to one thread?


Using modern C++, what is the best way to have some shared memory that is initialized by one thread, the first to get to this point, and then read by many threads? It needs to be as lightweight as possible.

int *ptr = nullptr;

void parallel_work() {
    // this should only done by the first thread to this point
    ptr = init_ptr();

    // all threads read After ptr is set 
    do_with(ptr);
}


int main() {
    std::thread th0 { &parallel_work };
    std::thread th1 { &parallel_work };
    std::thread th2 { &parallel_work };
    parallel_work();
}

If it can help, I really want to avoid wrapping the whole read part of the code in a mutex.

PS: this is not the use case for static function variables, as I'll be creating many of these in the program's lifetime.


Solution

  • std::call_once does exactly this.

    int *ptr = nullptr;
    std::once_flag flag;
    
    void parallel_work() {
        std::call_once(&flag, []() {
            ptr = init_ptr();
        });
    
        do_with(ptr);
    }
    

    It even forces other threads to wait until init_ptr is done and it synchronizes to make sure they all see the initialized value of ptr.