std :: async - 参数向量已损坏

时间:2014-12-06 20:31:09

标签: c++ multithreading c++11 asynchronous vector

我想将一个向量分成小向量,在一个线程上分别处理它们,然后合并它们。我想使用std::async来创建线程,我的代码看起来像这样

void func(std::vector<int>& vec)
{
   //do some stuff
}

// Calling part
std::vector<std::future<void>> futures;
std::vector<std::vector<int>> temps;
for (int i = 1; i <= threadCount; ++i)
{
    auto& curBegin = m_vec.begin() + (i - 1) * size / threadCount;
    auto& curEnd = m_vec.begin() + i * size / threadCount;
    std::vector<int> tmp(curBegin, curEnd);
    temps.push_back(std::move(tmp));

    futures.push_back(std::async(std::launch::async, &func, std::ref(temps.back())));
}
for (auto& f : futures)
{
    f.wait();
}

std::vector<int> finalVector;
for (int i = 0; i < temps.size() - 1; ++i)
{
    std::merge(temps[i].begin(), temps[i].end(), temps[i + 1].begin(), temps[i + 1].end(), std::back_inserter(finalVector));
}

这里m_vec是主矢量,它被分成小矢量。 问题是,当我将向量传递给func()时,在函数中它变为无效,大小为0或无效元素。但是当我尝试在没有std::async的情况下调用该函数时,一切正常。

那么std::async的问题是什么?我应该做些什么特别的事情?

感谢您的时间!

2 个答案:

答案 0 :(得分:5)

如果在迭代扩展temps向量时发生重新分配,那么线程操作的std::ref(temps.back())很可能是引用已经失效的内存区域。您可以通过在连续push_back s:

之前保留内存来避免重定位
temps.reserve(threadCount);

答案 1 :(得分:3)

Piotr S.已经用解决方案给出了正确答案,我只想补充一些解释。

  

那么std :: async的问题是什么?我应该做些什么特别的事情?

问题不在于async

如果你这样做,你会得到完全相同的效果:

std::vector<std::function<void()>> futures;
// ...
for (int i = 1; i <= threadCount; ++i)
{
  // ...
  futures.push_back(std::bind(&func, std::ref(temps.back())));
}
for (auto f : futures)
  f();

在这个版本中我没有使用async,我创建了几个函数对象,然后逐个运行它们。您将看到此代码存在同样的问题,即函数对象(或者在您的情况下,由async运行的任务)保存对插入temps时被销毁的向量元素的引用并使其重新分配。

要解决这个问题,你需要确保temps中的元素是稳定的,即不要在不同的位置销毁和重新创建,正如Piotr S在他的回答中所示。