构造std :: thread对象的过程中的细节

时间:2015-04-17 08:05:10

标签: c++ multithreading c++11 language-lawyer stdthread

我对构建std::thread对象的细节很感兴趣(并且很困惑)。根据{{​​3}},线程函数和所有参数都被值复制到一些线程可访问的存储,然后调用。

1)这个线程可访问的存储究竟是什么?它在语义上是否等同于某种线程本地存储,并且在线程函数返回后变量被破坏了?

2)传递给线程函数时参数的值类别是什么? cppreference的描述表明它们作为l值传递(无论如何它们都被赋予了名称)。我对GCC和clang的测试似乎暗示了相反的,即r值。具体来说,以下代码无法编译:

void f(int& a) {
  std::cout << ++a << '\n';
}

int main() {
    std::thread t(&f, 1);
    t.join();
    return 0;
}

如果我们将f更改为

,则会进行编译
void f(int&& a) {
  std::cout << ++a << '\n';
}

int main() {
    std::thread t(&f, 1);
    t.join();
    return 0;
}

那么,标准对此有何看法?

1 个答案:

答案 0 :(得分:3)

1)这个&#34;线程可访问的存储&#34;文本位不直接在标准中表示。标准只是说用decay_copy获得的参数调用函数。

2)如果你仔细研究decay_copy,你会发现它按值返回 (因为它的返回类型是std::decay的东西)。因此,函数f使用rvalue参数调用(实际上是prvalue参数)。

如果要传递左值(引用),可以使用std::refstd::cref来包装它们。

确切的引用,C ++ 11 30.3.1.2/4:

  

效果:构造一个thread类型的对象。新的执行线程执行 INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) 并调用    DECAY_COPY 在构造线程中进行评估。此调用的任何返回值都是   忽略。 [注意:这意味着调用f副本时不会抛出任何异常   将抛出构造线程,而不是新线程。 -end note ]如果调用    INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) 终止   如果未被捕获,则应调用std::terminate

DECAY_COPY 在30.2.6 / 1中定义:

  

在本条款的几个地方,使用了 DECAY_COPY(x) 操作。所有这些用途都意味着调用函数   decay_copy(x)并使用结果,其中decay_copy的定义如下:

template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }

INVOKE 在20.8.2中的定义与cppreference描述您所提供的链接中的调用的方式非常相似。