You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ for循环创建多线程丢失首次迭代的问题排查与解决

问题与解决:线程创建时循环变量引用捕获导致的未定义行为

问题场景

开发需要可变数量线程的应用,通过vector管理线程,但运行时出现循环首次迭代输出缺失、最终输出垃圾值的问题。

复现代码

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

std::mutex my_mutex;

void print_func(int idx){
    std::lock_guard<std::mutex> f(my_mutex);
    std::cout << "Thread id: " << idx << std::endl;
}

int main() {

    const auto processor_count = 4;
    std::vector<std::thread> ThreadVector;

    for(int i = 0; i < processor_count; i++){
        ThreadVector.emplace_back([&](){print_func(i);});
    }

    for(auto& t: ThreadVector){
        t.join();
    }
    return 0;
}

实际输出

Thread id: 1
Thread id: 2
Thread id: 3
Thread id: -214744752

预期输出

Thread id: 0
Thread id: 1
Thread id: 2
Thread id: 3

问题原因

核心问题在于lambda表达式使用**引用捕获[&]**获取循环变量i:

  • 线程创建后不会立即执行,当线程真正启动时,循环可能已经完成多次迭代,甚至已经结束。此时引用的i值已经不是线程创建时的初始值。
  • 循环结束后,i的值会变为processor_count(即4),随后这个局部变量被销毁。线程再访问已销毁变量的引用,会触发未定义行为,输出随机垃圾值。
  • 所谓“跳过首次迭代”是错觉:第一个线程运行时,i已经被更新为1,所以输出1而非0,并非真的跳过了迭代。

解决方案

有两种可靠的修复方式:

1. 值捕获循环变量

将lambda的捕获方式改为值捕获,让每个线程持有i的独立副本:

for(int i = 0; i < processor_count; i++){
    ThreadVector.emplace_back([i](){print_func(i);});
}

2. 直接传递参数给线程构造函数

利用std::thread构造函数支持直接传参的特性,完全规避捕获变量的生命周期问题:

for(int i = 0; i < processor_count; i++){
    ThreadVector.emplace_back(print_func, i);
}

修复后运行代码,输出将完全符合预期。

内容的提问来源于stack exchange,提问作者pwswierczynski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:56:29