OpenMP并行区域中的这个std :: vector push_back会导致错误共享吗?

时间:2017-11-14 08:02:50

标签: c++ openmp stdvector false-sharing

下面的示例代码是我的工作代码的简化版本。在此代码中,只能在调用std::vector::push_back的最后一行写入共享变量。

std::vector<struct FortyByteStruct> results;

#pragma omp parallel for num_threads(8)
for (int i = 0; i < 250; i++)
{
    struct FortyByteStruct result = some_heavy_work(i);

    #pragma omp critical
    {
        results.push_back(result);
    }
}

我想知道这个push_back操作是否会导致错误共享,让我有机会通过摆脱它来进一步优化。在深入研究这个问题之前,我已经决定先做一些基准测试。

使用chrono,我分别测量了some_heavy_work()和关键部分的挂钟执行时间。后者占用了前者的执行时间 10 ^( - 4)次,因此我得出结论,无论是否涉及虚假共享,优化此部分几乎没有任何好处。不

无论如何,我仍然很好奇虚假分享是否是一个问题。我是否必须查看std::vector的内部实现?任何启发将不胜感激。 (我在VS2015上)

2 个答案:

答案 0 :(得分:3)

鉴于您的FortyByteStruct可能小于缓存行(通常为64字节),在写入结果数据时可能会有一些错误共享。然而,这几乎不是重要因素,因为它会被关键部分的成本所掩盖 - 而且还会使真正的&#34;共享修改vector本身(不是它的数据)。您不需要知道std::vector实现的详细信息 - 只是它的数据在内存中是连续的并且它的状态(指针)数据/大小/容量)在矢量变量本身的内存中。当多个线程以不受保护的方式访问同一缓存行上的单独数据时,虚假共享通常是一个问题。请注意,虚假共享不会影响正确性,只影响性能

当您拥有std::vector<std::vector<struct FortyByteStruct>>且每个线程执行不受保护的push_back时,错误共享的示例略有不同。我详细解释了here

在您的示例中,使用已知的向量总大小,最好的方法是在循环之前调整向量的大小,然后只分配results[i] = result。这避免了关键部分,OpenMP通常以几乎没有错误共享的方式分配循环迭代。您还可以获得results的确定性顺序。

那就是说,当你通过测量确认时间由some_heavy_work支配时,你就可以了。

答案 1 :(得分:0)

我不是std :: vector实现的专家,但我很确定它不会检查另一个进程是否同时写入。

尽管如此,这里有两条建议:

  • 是的,关键操作的开销很小,但与并行执行'some_heavy_work'的增益相比,它可以忽略不计(我猜......)。所以,有疑问,我会把它留在那里

  • 您应该检查关键和原子(openMP, atomic vs critical?)之间的区别。

希望有所帮助