我正在尝试在循环中创建不同的线程并将它们存储在线程向量中。
编辑1 :线程数由用户指定。
const int numThreads = stoi(argv[3]);
初始代码:
vector<thread> vectorThreadsFFT{(unsigned long) (numThreads)};
for (int i = 0; i < numThreads; ++i) {
vectorThreadsFFT.emplace_back(
move(thread{FFT, ref(vectorBuffersUC), ref(vectorBuffersCD), ref(i), ref(numThreads)}));
}
编辑2:我最后加入了主题。
for (int i = 0; i < numThreads; ++i) {
vectorThreadsFFT[i].join();
}
当我调试代码时,我得到分段错误(signal = SIGABRT)。我已尝试删除move子句并将emplace_back()
更改为push_back()
,但我仍然得到相同的结果。
编辑3:当我为这另一个函数创建一个线程时,它有时会崩溃(但不是每次都崩溃),如:
thread th2{separator, ref(vectorBuffersUC), ref(numThreads), ref(nitems)};
以下是哪个标题:
void separator(vector<unique_ptr<lockedBufferUC>> &vectorBuffersUC, int numThreads, const long nitems){}
我开始怀疑这是因为我给矢量的参数以及函数如何接收它们。
我是否遗漏了有关C ++ 11和线程管理的内容?
随时询问更多详情或代码。
解决方案:
答案 0 :(得分:2)
代码没有按照您的预期执行。
vector<thread> vectorThreadsFFT{(unsigned long) (numThreads)};
这会正确调整向量的大小以容纳numThreads
个元素。但是,emplace_back
或push_back
之后的这种初始化会在numThreads
索引处添加一个元素,而不是0
,如您所料。
在这里做的几个正确的事情之一是首先reserve
向量,然后做emplace_back
。
此外,move
不是必需的。通过优化,编译器足够智能,可以进行现场构建。
另一件事是,除非你是join
,否则你必须detaching
线程。 joinable
个线程如果没有加入销毁调用std::terminate
。
const int numThreads = stoi(argv[3]);
vector<thread> vectorThreadsFFT;
vectorThreadsFFT.reserve(numThreads);
for (int i = 0; i < numThreads; ++i) {
vectorThreadsFFT.emplace_back(
std::thread {FFT, ref(vectorBuffersUC), ref(vectorBuffersCD), i, ref(numThreads)} );
}
for (int i = 0; i < numThreads; ++i) {
vectorThreadsFFT.join();
}
答案 1 :(得分:2)
您将对i
的引用传递给线程的闭包,因此在循环结束后它立即变为无效。尝试仅按值传递id
:
for (int i = 0; i < numThreads; ++i) {
vectorThreadsFFT.emplace_back(
thread{FFT, ref(vectorBuffersUC), ref(vectorBuffersCD), i, ref(numThreads)});
}
此外,您不应将std::move
用于thread{}
之类的右移对象。
而且,正如@Arunmu所提到的,在向量被破坏之前,你不能忘记join
所有线程(它会导致terminate
,见docs)。
更好的解决方案是使用std::async
不要手动处理加入。此外,它允许您使用延迟执行和更好的并行可扩展方法(请参阅docs)。