Lin*_*gxi 6 c++ multithreading language-lawyer c++11 stdthread
我对构造std::thread对象的细节很感兴趣(并对此感到困惑)。根据cppreference,线程函数和所有参数都被值复制到一些线程可访问的存储中,然后调用。
1)这个线程可访问的存储究竟是什么?是不是语义上等同于某种线程本地存储,在线程函数返回后销毁变量?
2) 传递给线程函数时参数的值类别是什么?cppreference 上的描述表明它们作为左值传递(无论如何它们都被赋予了名称)。我对 GCC 和 clang 的测试似乎表明相反,即 r 值。具体来说,以下代码无法编译:
void f(int& a) {
std::cout << ++a << '\n';
}
int main() {
std::thread t(&f, 1);
t.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我们f改为
void f(int&& a) {
std::cout << ++a << '\n';
}
int main() {
std::thread t(&f, 1);
t.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
那么,标准对此有何看法?
1) 这个“线程可访问存储”文本位在标准中没有直接表示。该标准只是简单地说该函数是用 获得的参数调用的decay_copy。
2)如果你decay_copy仔细研究,你会发现它是按值返回的(因为它的返回类型是std::decaysomething)。因此,该函数f是使用右值参数(实际上是纯右值参数)调用的。
如果要传递左值(引用),可以使用std::ref和std::cref来包装它们。
确切的引用,C++11 30.3.1.2/4:
\n\n\n\n\n作用:构造一个类型为 的对象
\nthread。新的执行线程通过在构造线程中评估INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)对\n 的调用来 执行。DECAY_COPY此调用的任何返回值都将被忽略。[注意:这意味着调用 \n 副本时未抛出的任何异常都f将在构造线程中抛出,而不是在新线程中抛出。\xe2\x80\x94end note ] 如果\n 的调用INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)因未捕获的异常而终止\n,std::terminate则应调用。
DECAY_COPY30.2.6/1 中定义:
\n\n\n本条款中的多个地方
\n\nDECAY_COPY(x)使用了该操作。所有这些使用都意味着调用函数decay_copy(x)并使用结果,其中decay_copy定义如下:Run Code Online (Sandbox Code Playgroud)\ntemplate <class T> typename decay<T>::type decay_copy(T&& v)\n{ return std::forward<T>(v); }\n
INVOKE在 20.8.2 中定义的方式与 cppreference 在您提供的链接中描述调用的方式几乎相同。
| 归档时间: |
|
| 查看次数: |
1126 次 |
| 最近记录: |