我想将一个向量分成小向量,在一个线程上分别处理它们,然后合并它们。我想使用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
的问题是什么?我应该做些什么特别的事情?
感谢您的时间!
答案 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在他的回答中所示。