关于C#:线程安全的静态变量初始化

Thread safety of static variable initialization

我想确定以下代码中具有不同参数类型的2个对Get()的调用是否是线程安全的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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++;
    }
};

一方面,在index初始化期间并根据标准,调用NextIndex()

1
?§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.

另一方面,我不知道对NextIndex()的调用是否被视为index初始化的一部分。如果没有,括号初始化有区别吗?

1
static size_t index{ NextIndex() };

或者,如果我不想使nextIndex成为原子,还有其他方法可以使其成为线程安全吗?


假设您有两个不同的功能:

1
2
3
4
5
6
7
8
static size_t get_int() {
    static size_t index = NextIndex();
    return index;
}
static size_t get_long() {
    static size_t index = NextIndex();
    return index;
}

您是否有疑问,从单独的线程调用这两个函数不是线程安全的?显然,对NextIndex的调用引起了数据竞争。

通过实例化模板函数来创建这些函数不会摆脱数据竞争。模板不是代码;它们是用于创建代码的模式。从两个不同的线程调用模板函数的两个不同的实例化(例如,Get<int>()Get<long>())会产生数据争用。