std::thread对象构造过程中的细节
Details in the process of constructing a std::thread object
我对构建 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;
}
如果我们把f
改成
就可以编译
void f(int&& a) {
std::cout << ++a << '\n';
}
int main() {
std::thread t(&f, 1);
t.join();
return 0;
}
那么,标准对此有何规定?
1) 此 "thread-accessible storage" 位文本未直接在标准中表示。该标准只是说该函数是用 decay_copy
.
获得的参数调用的
2)如果你仔细研究decay_copy
,你会发现它return是by value(因为它的return类型是std::decay
的东西)。所以函数 f
是用右值参数(实际上是纯右值参数)调用的。
如果你想传递左值(引用),你可以使用std::ref
和std::cref
来包装它们。
准确引用,C++11 30.3.1.2/4:
Effects: Constructs an object of type thread
. The new thread of execution executes INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
with the calls to
DECAY_COPY
being evaluated in the constructing thread. Any return value from this invocation is
ignored. [ Note: This implies that any exceptions not thrown from the invocation of the copy of f
will be thrown in the constructing thread, not the new thread. —end note ] If the invocation of
INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
terminates
with an uncaught exception, std::terminate
shall be called.
DECAY_COPY
定义在30.2.6/1:
In several places in this Clause the operation DECAY_COPY(x)
is used. All such uses mean call the function
decay_copy(x)
and use the result, where decay_copy
is defined as follows:
template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }
INVOKE
在 20.8.2 中的定义与 cppreference 在您提供的 link 中描述调用的方式几乎相同。
我对构建 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;
}
如果我们把f
改成
void f(int&& a) {
std::cout << ++a << '\n';
}
int main() {
std::thread t(&f, 1);
t.join();
return 0;
}
那么,标准对此有何规定?
1) 此 "thread-accessible storage" 位文本未直接在标准中表示。该标准只是说该函数是用 decay_copy
.
2)如果你仔细研究decay_copy
,你会发现它return是by value(因为它的return类型是std::decay
的东西)。所以函数 f
是用右值参数(实际上是纯右值参数)调用的。
如果你想传递左值(引用),你可以使用std::ref
和std::cref
来包装它们。
准确引用,C++11 30.3.1.2/4:
Effects: Constructs an object of type
thread
. The new thread of execution executesINVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
with the calls toDECAY_COPY
being evaluated in the constructing thread. Any return value from this invocation is ignored. [ Note: This implies that any exceptions not thrown from the invocation of the copy off
will be thrown in the constructing thread, not the new thread. —end note ] If the invocation ofINVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
terminates with an uncaught exception,std::terminate
shall be called.
DECAY_COPY
定义在30.2.6/1:
In several places in this Clause the operation
DECAY_COPY(x)
is used. All such uses mean call the functiondecay_copy(x)
and use the result, wheredecay_copy
is defined as follows:template <class T> typename decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }
INVOKE
在 20.8.2 中的定义与 cppreference 在您提供的 link 中描述调用的方式几乎相同。