循环添加std::thread与逐个添加结果不同的原因排查
问题原因与解决方法
核心问题:Lambda捕获循环变量的引用陷阱
循环中你用[&]捕获了所有变量的引用,包括循环变量i。但线程是异步执行的——线程真正开始运行时,循环可能已经迭代了多次,甚至已经结束,此时i的值早已不是创建线程时的数值,导致计算出的start和end完全不符合预期:
- 第一次循环的线程启动时,
i可能已经变成了3或4,算出的end就会是dataSize*4或dataSize*5,直接越界。 - 即使提前计算了
start和end,但lambda里还是用了dataSize*i,依然捕获的是i的引用,线程执行时i的值已经变化,导致参数错误,最终顶点生成不完整。
正确实现方式
要让每个线程拿到创建时的i值,需要捕获循环变量的副本,而不是引用。有两种简单的写法:
写法1:循环内创建局部变量保存当前i,值捕获该变量
for (int i = 0; i < 4; ++i) { int current_i = i; // 用局部变量固定当前迭代的i值 // 用[=]值捕获所有变量,或明确指定捕获的变量 threads.push_back(std::thread([=]() { CalculateVertices(vertex_scale, texture_scale, dataSize * current_i, dataSize * (current_i + 1), data); })); }
写法2:直接在lambda中按值捕获i
for (int i = 0; i < 4; ++i) { // 明确按值捕获i,其他需要的变量按需捕获(引用或值) threads.push_back(std::thread([i, &vertex_scale, &texture_scale, dataSize, data]() { CalculateVertices(vertex_scale, texture_scale, dataSize * i, dataSize * (i + 1), data); })); }
额外注意事项
- 线程创建后必须调用
join()等待所有线程完成,否则程序退出时会触发未定义行为:// 循环结束后等待所有线程执行完毕 for (auto& thread : threads) { thread.join(); } - 你的代码中每个线程处理不同的
z区间,操作的vertices和textureCoords下标无重叠,不存在线程竞争,这部分是安全的。
内容的提问来源于stack exchange,提问作者yuhao
相关产品推荐
相关产品推荐

