使用std::thread类时,为什么我可以传递通过引用捕获变量的lambda表达式?

问题描述 投票:0回答:1

我很难理解以下 std::thread 的注释(来自 cppref):

线程函数的参数按值移动或复制。如果需要将引用参数传递给线程函数,则必须对其进行包装(例如,使用 std::refstd::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
也没有移动它,因为它在主线程末尾是安全无害的。可调用对象通过引用捕获它,那么为什么允许这样做?

c++ multithreading stdthread
1个回答
0
投票

您的第一个示例不会失败,因为编译器知道变量的生命周期。由于这个非常具体的原因,它失败了:

**/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/std_thread.h:129:72:错误:静态断言失败:std::thread 参数在转换后必须可调用到右值 **

第二个版本没有这个问题,所以是允许的。

编译器无法跨线程跟踪变量范围并知道您的程序应该做什么。这基本上可以解决停止问题。

© www.soinside.com 2019 - 2024. All rights reserved.