【问题标题】:Problems creating vector of threads in a loop在循环中创建线程向量的问题
【发布时间】:2016-12-09 14:54:21
【问题描述】:

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

EDIT 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();
}

当我调试代码时,出现分段错误(信号 = 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 的引用

【问题讨论】:

  • 如果你只是创建例如它是否有效?十个线程不在一个向量中?只是想找出问题所在。
  • @KennyOstrom 不,我刚刚尝试创建三个线程,但它在第一个线程上中止。
  • 好的。所以这与“线程向量”无关,与“创建线程”有关。那么它如何崩溃了?如果只调用线程函数,它会运行吗?
  • 另外,vector&lt;thread&gt; vectorThreadsFFT{(unsigned long) (numThreads)} 创建了一个带有numThreads 元素的向量——所有这些元素都不对应于线程。 emplace_back(或push_back)然后创建另一个元素。你需要的是vector&lt;thread&gt; vectorThreadsFFT;,或者如果你真的坚持,vector&lt;thread&gt; vectorThreadsFFT; vectorThreadsFFT.reserve(numThreads);
  • @danielsto:因为这就是emplace_back 存在的全部原因——你传入构造函数参数,它调用构造函数以便在向量中就地构造对象。

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


【解决方案1】:

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

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();
}

【讨论】:

  • 我最后会加入他们。我要编辑问题。
  • 我想你忘记了数组订阅。 vectorThreadsFFT[i].join();
【解决方案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 所提到的,在vector 被销毁之前,你不能忘记join 的所有线程(它会导致terminate,参见docs)。

更好的解决方案是使用std::async 不手动处理加入。此外,它将允许您使用延迟执行和更好的并行可扩展方法(请参阅docs)。

【讨论】:

    猜你喜欢
    • 2016-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    • 2023-04-08
    • 1970-01-01
    相关资源
    最近更新 更多