在循环中创建线程向量的问题

时间:2016-12-09 14:54:22

标签: c++ multithreading c++11 vector segmentation-fault

我正在尝试在循环中创建不同的线程并将它们存储在线程向量中。

编辑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和线程管理的内容?

随时询问更多详情或代码。

解决方案:

  • 预留空间
  • 通过值传递i的引用

2 个答案:

答案 0 :(得分:2)

代码没有按照您的预期执行。

vector<thread> vectorThreadsFFT{(unsigned long) (numThreads)};

这会正确调整向量的大小以容纳numThreads个元素。但是,emplace_backpush_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)。