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
相关产品推荐
相关产品推荐

