我很难理解以下 std::thread 的注释(来自 cppref):
线程函数的参数按值移动或复制。如果需要将引用参数传递给线程函数,则必须对其进行包装(例如,使用 std::ref 或 std::cref)。
好吧 - 因为不能保证参数在线程执行结束之前一直保持活动状态,所以线程本身应该拥有它是有道理的。现在,考虑以下代码片段:
#include <iostream>
#include <thread>
void
tellValue(int& value)
{
std::cout << "The value is: " << value << std::endl;
}
int
main()
{
int mainThreadVariable{0};
std::thread thr0{tellValue, mainThreadVariable};
thr0.join();
return 0;
}
Clang 不接受这个,也不应该接受——该线程不拥有
mainThreadVariable
。然而,为什么它接受这一点:
#include <iostream>
#include <thread>
int
main()
{
int mainThreadVariable{0};
std::thread thr0{[&]()
{
std::cout << "The value is: " << mainThreadVariable
<< std::endl;
++mainThreadVariable;
}};
thr0.join();
std::cout << "The value is: " << mainThreadVariable << std::endl;
return 0;
}
后者输出以下内容:
./PassingArgumentsToAThread
The value is: 0
The value is: 1
线程既没有复制
mainThreadVariable
也没有移动它,因为它在主线程末尾是安全无害的。可调用对象通过引用捕获它,那么为什么允许这样做?
您的第一个示例不会失败,因为编译器知道变量的生命周期。由于这个非常具体的原因,它失败了:
**/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/std_thread.h:129:72:错误:静态断言失败:std::thread 参数在转换后必须可调用到右值 **
第二个版本没有这个问题,所以是允许的。
编译器无法跨线程跟踪变量范围并知道您的程序应该做什么。这基本上可以解决停止问题。