C++ 线程安全和静态变量/成员函数

C++ 线程安全和静态变量/成员函数,c++,thread-safety,c++14,static-initialization,C++,Thread Safety,C++14,Static Initialization,这不是关于静态初始化和线程安全的问题。由于标准中使用的措辞,自C++11以来,它们一起得到保证。 到目前为止,一切顺利。请考虑下面的类: struct S { static int id() noexcept { static int v = 0; return v++; } template<typename> static int value() noexcept { static const in

这不是关于静态初始化和线程安全的问题。由于标准中使用的措辞,自C++11以来,它们一起得到保证。
到目前为止,一切顺利。请考虑下面的类:

struct S {
    static int id() noexcept {
        static int v = 0;
        return v++;
    }

    template<typename>
    static int value() noexcept {
        static const int v = id();
        return v;
    }
};
结构{
静态int id()无异常{
静态int v=0;
返回v++;
}
模板
静态int值()无异常{
静态常量int v=id();
返回v;
}
};
在这种情况下,在不同线程上对
S::value()
进行的两个并发调用是安全的(如果我错了,请纠正我)

S::value()
S::value()
这样的两个并发调用也安全吗

就我所见,
value
本身并不是一个问题,因为不同的专门化。但是,在调用
id
时,保证第一行(静态初始化)是线程安全的,但这并不适用于紧接其后的行。
因此,
v
对于
value
中的
attype
AnotherType
可以具有相同的值
另一方面,
id
value
中的
v
的静态初始化过程中被调用,因此我不确定我的期望是否有效。

这就是我问的原因。我的推理是否有问题,或者上面的代码实际上不是线程安全的?

没有。您必须进行同步,但在您的情况下,它非常简单:

struct S {
    static int id() noexcept {
        static std::atomic<int> v { 0 };
        return ++v;
    }

    template<typename>
    static int value() noexcept {
        static const int v = id();
        return v;
    }
};
结构{
静态int id()无异常{
静态std::原子v{0};
return++v;
}
模板
静态int值()无异常{
静态常量int v=id();
返回v;
}
};

注意,避免后增量是一种很好的做法。

避免后增量的结果是,在您的情况下,永远不会返回0。实际上,这不是我能接受的,而且
v
size\u t
。因此,不幸的是,我无法避免后期初始化。您可以将您的问题与
fetch\u add
结合起来,以维护后期增量行为。