构造std::thread对象过程中的详细信息

Details in the process of constructing a std::thread object

本文关键字:详细信息 过程中 thread std 构造 对象      更新时间:2023-10-16

我对构造std::thread对象的细节很感兴趣(也很困惑)。根据cppreference,线程函数和所有参数都被值复制到某个线程可访问的存储中,然后调用。

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

2)传递给线程函数时,参数的值类别是什么cppreference上的描述表明它们是作为l-value传递的(不管怎样,它们都是给定的名称)。我对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)这个"线程可访问存储"的文本位在标准中没有直接表示。标准只是简单地说,函数是用decay_copy获得的参数调用的。

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

如果要传递lvalues(references),可以使用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副本时未抛出的任何异常将在构造线程中抛出,而不是在新线程中抛出-结束注释]如果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描述您提供的链接中的调用的方式大致相同。