我对构建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;
}
那么,标准对此有何看法?
答案 0 :(得分:3)
1)这个&#34;线程可访问的存储&#34;文本位不直接在标准中表示。标准只是说用decay_copy
获得的参数调用函数。
2)如果你仔细研究decay_copy
,你会发现它按值返回 (因为它的返回类型是std::decay
的东西)。因此,函数f
使用rvalue参数调用(实际上是prvalue参数)。
如果要传递左值(引用),可以使用std::ref
和std::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描述您所提供的链接中的调用的方式非常相似。