If you’re happy to lean on the compiler’s built-in function static thread safety, then you could do it without a lock, just using a function-local static whose constructor does the initialisation.
(I think all modern compilers support thread-safe local statics)
such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. […] If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.