如何在C++中拼接std::thread多线程生成的LibTorch张量
问题分析
你的核心问题是线程执行的异步性:直接在创建线程后拼接,此时线程可能还未完成函数调用,对应位置的张量未生成;或是多线程无同步地修改共享结果容器,引发内存竞争错误。正确思路是先让所有线程完成任务并将结果存入对应索引的容器,再统一按顺序拼接。
正确实现步骤
- 预分配结果容器:根据调用次数创建固定大小的容器,每个位置对应一个线程的返回张量。
- 线程绑定索引:每个线程执行函数后,将结果存入容器的指定索引位置(若每个线程仅操作独立索引,无需加锁;涉及共享资源时需用互斥量保护)。
- 等待所有线程完成:调用
std::thread::join()确保所有线程执行完毕,避免访问未初始化的结果。 - 按索引顺序拼接所有张量为大张量。
代码示例
原尝试错误代码(常见问题)
#include <thread> #include <vector> #include <Eigen/Dense> // 假设使用Eigen张量库 Eigen::RowVectorXd generate_tensor() { Eigen::RowVectorXd tensor(8); tensor.setRandom(); // 模拟生成张量逻辑 return tensor; } int main() { const int call_times = 12; Eigen::MatrixXd result(0, 8); std::vector<std::thread> threads; for (int i = 0; i < call_times; ++i) { threads.emplace_back([&]() { auto tensor = generate_tensor(); // 错误:多线程同时修改result会引发数据竞争 result.conservativeResize(result.rows() + 1, Eigen::NoChange); result.row(result.rows() - 1) = tensor; }); // 错误:未等待线程完成就继续循环,后续拼接会访问未初始化内存 } // 未调用join,程序退出时线程可能仍在运行 return 0; }
正确实现代码
#include <thread> #include <vector> #include <Eigen/Dense> // 生成1×8张量的函数 Eigen::RowVectorXd generate_tensor() { Eigen::RowVectorXd tensor(8); tensor.setRandom(); // 模拟生成逻辑 return tensor; } int main() { const int call_times = 12; // 预分配结果容器,每个位置对应一个线程的结果 std::vector<Eigen::RowVectorXd> results(call_times); std::vector<std::thread> threads; for (int i = 0; i < call_times; ++i) { // 按值捕获索引i,避免闭包引用共享变量导致的索引混乱 threads.emplace_back([i, &results]() { results[i] = generate_tensor(); // 每个线程仅写入自己的索引位置,无数据竞争,无需加锁 }); } // 等待所有线程执行完毕 for (auto& t : threads) { t.join(); } // 拼接所有张量为12×8的大张量 Eigen::MatrixXd final_result(call_times, 8); for (int i = 0; i < call_times; ++i) { final_result.row(i) = results[i]; } // 输出验证(可选) std::cout << final_result << std::endl; return 0; }
CMakeLists.txt配置
需要链接线程库(Linux下为pthread),若使用Eigen则引入对应库:
cmake_minimum_required(VERSION 3.10) project(tensor_thread_demo) set(CMAKE_CXX_STANDARD 17) # 寻找Eigen库(使用自定义张量可移除此段) find_package(Eigen3 REQUIRED) add_executable(tensor_thread_demo main.cpp) # 链接依赖库 target_link_libraries(tensor_thread_demo PRIVATE Eigen3::Eigen) # Linux下需链接pthread,Windows无需 if(UNIX) target_link_libraries(tensor_thread_demo PRIVATE pthread) endif()
关键注意点
- 闭包索引捕获:必须按值捕获
i,否则所有线程会共享同一个i的引用,导致结果存入错误索引。 - 线程同步:必须调用
join()等待所有线程完成,否则结果容器可能存在未初始化的张量。 - 无锁条件:当每个线程仅写入容器的独立索引位置时,无需加锁;若涉及全局共享资源,则需要用
std::mutex保护访问。
内容的提问来源于stack exchange,提问作者Ant
相关产品推荐
相关产品推荐

