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::refstd::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 中描述调用的方式几乎相同。