c++11 - 模板变量线程安全吗?它们放在数据段上?

标签 c++11 thread-safety c++14 data-segment variable-templates

我正在使用 C++14 中的新模板变量功能以适应它(也许很快就会这样做,因为似乎有些编译器没有完全实现它)。

现在我想知道模板变量的每个实例在哪里。在我到目前为止所做的测试中,它们似乎在任何静态数据之前被初始化,所以我想知道它们是否被放置在 data segment 中。的程序。让我们看看到目前为止我已经尝试过什么,我有一个打印有关构造和销毁信息的类:

struct squealer
{
    squealer(std::string a_name) : m_name(a_name) { std::cout << this << ' ' << m_name << ' ' << __PRETTY_FUNCTION__ << '\n'; }
    ~squealer() { std::cout << this << ' ' << m_name << ' ' << __PRETTY_FUNCTION__ << '\n'; }
    void f() {}
    const std::string m_name;
};

还有一个程序,它实例化了一些 squealer s 在本地存储、静态存储和作为模板变量,这是程序:
// static storage squealer
squealer s("\"static\"");

// template variable squealer
template <int i> squealer test(std::string(i, 'A'));

// function using a template variable squealer
void f() { test<1>.f(); }

int main(int argc, char **argv)
{
    // local storage squealer
    squealer ss("local");

    // using another template variable squealers
    test<2>.f();
    switch (argc)
    {
        case 1: test<3>.f(); break;
        case 2: test<4>.f(); break;
        case 3: test<5>.f(); break;
        case 4: test<6>.f(); break;
    }

    return 0;
}

Here is the program这是输出:
A squealer::squealer(std::string)
AA squealer::squealer(std::string)
AAA squealer::squealer(std::string)
AAAA squealer::squealer(std::string)
AAAAA squealer::squealer(std::string)
AAAAAA squealer::squealer(std::string)
"static" squealer::squealer(std::string)
local squealer::squealer(std::string)
local squealer::~squealer()
"static" squealer::~squealer()
AAAAAA squealer::~squealer()
AAAAA squealer::~squealer()
AAAA squealer::~squealer()
AAA squealer::~squealer()
AA squealer::~squealer()
A squealer::~squealer()

如我们所见,所有模板变量 squealer在名为 "static" 的实例之前创建实例最后(如预期的那样)名为 local被创建,销毁顺序是相反的(也正如预期的那样),所以:模板变量实例的创建/初始化顺序与其在代码中的出现顺序相同,而不管这种出现的位置如何,也不管它们是否被使用与否(从不调用 f() 函数)。

那么第一个问题是,这个模板变量是放在数据段上的吗?我不知道如何测试或检查它。

第二个问题是,这些模板变量都是squealer吗?实例线程安全?我读过 n3376 §6.7以下句子(强调我的):

An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise 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 the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.



从 C++11 如果所有模板变量 squealer实例在静态存储中,它们应该是线程安全的,不是吗?

谢谢。

最佳答案

您引用的标准部分描述了 块作用域 具有静态存储持续时间的变量,例如:

int foo() {
  static int bar = 42;
  return bar;
}

其中您的程序没有。所有具有静态存储持续时间的变量都在命名空间范围内声明,因此您需要查看 [basic.start.init] (3.6.2)。特别是第二段,其中指出:

Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.

...

Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, and otherwise is ordered [ Note: an explicitly specialized static data member or variable template specialization has ordered initialization. —end note ] Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization.



在问题的程序中,所有squealersquealer 起必须动态初始化具有静态存储持续时间的实例有成员(member)std::string不能被常量初始化。 ::s已下令初始化,以及 test 的所有实例具有无序的初始化,因为每个都是模板的“隐式或显式实例化”test . test实例保证在进入 main 之前被初始化,但除此之外,所有赌注都将关闭:它们可以以任何顺序初始化,可能在 ::s 初始化之前和/或之后。更重要的是std::cout .这些初始化显然不是线程安全的:“如果程序启动了一个线程,则变量的后续无序初始化相对于其他所有动态初始化都是无序的。”

关于c++11 - 模板变量线程安全吗?它们放在数据段上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29230353/

相关文章:

java - java中同步块(synchronized block)的替代方案

java - 这个 Singleton 是线程安全的吗?我看不出来怎么办?

c++ - 如何创建类似于 QVariant 的 Variant 类

c++ - g++未知/tmp/cc21HhMd.o:在函数`main::{lambda(编译错误

c++ - 现在允许使用虚拟基移动赋值运算符有危险吗?

c++ - 没有编译器 Hook ,哪些<type_traits>无法实现?

c++ - 如何检查类是否具有默认构造函数,公共(public)的、 protected 或私有(private)的

java - 空引用的安全初始化

c++ - 清理值而不向上或向下舍入

c++ - gcc 4.8 或更早版本是否存在关于正则表达式的问题?