Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread safety of static variable initialization

I want to find out whether 2 calls to Get() with different parameter types in the code below are thread-safe:

struct MethodTypeIndex
{
    template <typename T>
    static size_t Get(T)
    {
        static size_t index = NextIndex();
        return index;
    }
private:
    static size_t NextIndex()
    {
        static size_t nextIndex = 0;
        return nextIndex++;
    }
};

On the one hand, NextIndex() is called during the initialization of index and according to standard:

§6.7 [stmt.dcl] p4

If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

On the other hand, I don't know if call to NextIndex() is considered as part of initialization of index. And if not, does brace-initialization make difference?

static size_t index{ NextIndex() };

Or is there any other ways to make it thread safe, if I don't want to make nextIndex atomic?

like image 255
NuPagadi Avatar asked Oct 17 '17 12:10

NuPagadi


People also ask

Is static initialization thread-safe?

Starting in C++11, scoped static initialization is now thread-safe, but it comes with a cost: Reentrancy now invokes undefined behavior.] The rule for static variables at block scope (as opposed to static variables with global scope) is that they are initialized the first time execution reaches their declaration.

Is static variable thread-safe?

Static variables are not thread safe. Instance variables do not require thread synchronization unless shared among threads. But, static variables are always shared by all the threads in the process. Hence, access to static variable is not thread safe.


1 Answers

Pretend for a moment that you have two different functions:

static size_t get_int() {
    static size_t index = NextIndex();
    return index;
}
static size_t get_long() {
    static size_t index = NextIndex();
    return index;
}

Is there any doubt in your mind that calling these two functions from separate threads is not thread-safe? Clearly there’s a data race in the calls to NextIndex.

Creating those functions by instantiating a template function doesn’t get rid of the data race. Templates are not code; they are patterns for creating code. Calling two different instantiations of your template function (for example, Get<int>() and Get<long>()) from two different threads produces a data race.

like image 191
Pete Becker Avatar answered Oct 19 '22 20:10

Pete Becker