将超出范围的 lambda 函数传递给 std::thread 是否安全

Luc*_*ckk 9 c++ multithreading c++11

考虑以下代码:

#include <iostream>
#include <thread>
#include <chrono>

int main()
{
    std::thread t;
    {
        auto my_lambda = []{
           int idx = 0;
           while (true) {
               std::this_thread::sleep_for (std::chrono::seconds(1));
               std::cout << idx ++ << std::endl;
           } 
        };
        t = std::thread(my_lambda);
    }
    t.join();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

线程运行超出范围的 lambda 函数是否安全?

我看到 的构造函数std::thread采用输入函数的通用引用Function&& f,并且 lambda 被转换为结构。因此,如果结构体的实例在作用域内实例化,则线程将运行operator()悬空引用。

{
    struct lambda_translated { void operator()(){ ... } };
    lambda_translated instance;
    t = std::thread(instance);
}

Run Code Online (Sandbox Code Playgroud)

但我不确定我的推理是否正确。

附带问题:如果我在构造函数内将 lambda 声明为 R 值,行为是否会改变std::thread

#include <iostream>
#include <thread>
#include <chrono>

int main()
{
    std::thread t;
    {
        
        t = std::thread([]{
           int idx = 0;
           while (true) {
               std::this_thread::sleep_for (std::chrono::seconds(1));
               std::cout << idx ++ << std::endl;
           } 
        });
    }
    t.join();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

cbu*_*art 3

作为评论摘要:

lambda 被复制(或者如果就地声明则被移动),因此不会出现问题。

您必须担心捕获:不要通过引用捕获可能超出范围的对象,或者如果您传递可以在线程执行期间删除的对象(即使复制,请考虑指向对象的原始指针)。


作为扩展,如果您用于std::bind传递方法并且对象超出范围或被删除,则同样适用。