【问题标题】:Why this lambda function in loop didn't capture the parameter by value?为什么循环中的这个 lambda 函数没有按值捕获参数?
【发布时间】:2016-05-07 18:29:40
【问题描述】:

我有以下代码块,我期望的是 lambda 捕获列表中的 i 是按值传递的,而输出的 i 应该不同。

但是,实际结果是输出20行19 is completed

我尝试将这一行 std::thread t([&func](){ 更改为 std::thread t([func](){,输出可能会打印不同的 i 值。

我的问题是为什么std::thread t([&func](){std::thread t([func](){会导致i的输出值不同?

void DoSomething(std::function<void()> func)
{
    std::thread t([&func](){
        //do something
        sleep(1);
        if (func)
            func();
    });
    t.detach();
}

int main(int argc, const char * argv[]) {
    std::mutex mtx;
    for (int i = 1 ; i < 20; i ++) {
        DoSomething([i, &mtx](){
            std::unique_lock<std::mutex> lock(mtx);
            std::cout << i << " is completed" << std::endl;;
        });
    }
    sleep(10);
}

【问题讨论】:

    标签: c++ c++11 lambda


    【解决方案1】:

    您正在捕获对DoSomething 参数func 的引用。
    到您的线程执行时,该参数的生命周期已经结束,因此您有一个悬空引用并且使用它是未定义的。

    【讨论】:

    • 是不是表示传递给DoSomething的func携带了捕获列表的信息?
    • @2power10 我不确定你在问什么。如果通过引用捕获,则需要确保引用的对象在使用时是有效的,否则程序是未定义的。按价值捕获是正确的做法。
    【解决方案2】:

    DoSomething() 中的线程对象t 接收对func 对象的引用,该对象按值传递。当func() 被执行时,它可能正在等待mutex 通过调用std::unique_lock&lt;std::mutex&gt; lock(mtx); 在此期间t.detach() 将被调用并且该函数将通过销毁按值参数func 退出。这将导致@molbidnilo 所说的悬空引用。

    这个问题可以通过调用t.join();而不是t.detach()来解决。

    【讨论】:

    • 使用t.join() 将阻止DoSomething,这就是我在这里使用t.detach() 的原因。我认为这个问题可以通过按值而不是引用来捕获函数来解决。
    【解决方案3】:

    如果你使用 t.detach(),线程是独立运行的,现在你通过引用传递函数对象,所以如果函数对象在独立线程试图引用时被销毁,那不会导致崩溃该程序。 但是如果你按值传递函数对象,这个问题就解决了。我在我的机器上测试了你的代码,当使用通过引用传递的函数对象时它崩溃了。

    【讨论】:

      猜你喜欢
      • 2021-05-19
      • 2018-12-11
      • 2013-08-05
      • 2021-08-04
      相关资源
      最近更新 更多