使用并行编程 C++ 计算/访问向量

Posted

技术标签:

【中文标题】使用并行编程 C++ 计算/访问向量【英文标题】:Calculations / Accessing Vectors using Parallel Programming C++ 【发布时间】:2016-11-18 17:07:49 【问题描述】:

我有一个矩阵:

std::vector<std::vector<double> >* p_mat_cache = 
    new std::vector<std::vector<double> >(3, std::vector<double>());

还有一个向量:

std::vector<double>* p_val_vec_1 = new std::vector<double>(*mpStages);

其中 'mpStages' 是一个 int 值。在某个时候,我应用了一个发生以下情况的函数:

pMatCache->at(1).push_back((*pValVec1)[j+1]);
pMatCache->at(2).push_back((*pValVec1)[j]);

(*pValVec2)[j] = fmax(*mpK - CalculateS(i, j), *mpD *(0.5 * (*pValVec1)[j+1] +
                      0.5*(*pValVec1)[j]));

pMatCache->at(0).push_back((*pValVec2)[j]);

pValVec1 和 pMatCache 对应本地名称。 pValVec2 是另一个长度为“mpStages-1”的向量。 'CalculateS' 如下:

double AbstractOptionSolver::CalculateS(int n, int i)

    return pow(*mpUp,i) * pow(*mpDown, n-i) * *mpS;

其中私有变量“*mpS”、“*mpUp”和“*mpDown”在代码执行期间不会改变。我正在尝试做的是并行运行其中的一部分,我认为可以按如下方式完成:

#pragma omp parallel

    pMatCache->at(1).push_back((*pValVec1)[j+1]);
    pMatCache->at(2).push_back((*pValVec1)[j]);

    (*pValVec2)[j] = fmax(*mpK - CalculateS(i, j), *mpD *(0.5 * (*pValVec1)[j+1] +
                          0.5*(*pValVec1)[j]));


pMatCache->at(0).push_back((*pValVec2)[j]);

但是,由于添加了“omp parallel”,即使我只有 omp 并行(仅包括推回),此代码也会不断崩溃。想知道是否有人知道为什么会这样?

我还试图进一步了解并行编程,以了解何时/何时我不能在函数中/上使用它,因为有时使某些方面并行导致此代码由于未知原因而崩溃。如果有人有任何资源可以帮助我解决这个问题,那就太好了。

【问题讨论】:

这里的比赛条件 即使我只是在矩阵@appleapple 的两个不同位置应用推回? 【参考方案1】:

首先,#pragma omp parallel 只会在此时生成一堆线程,这些线程将在作用域部分执行完全相同的操作,它不会为每个线程分配唯一的 j 或 i。您可能想查看http://bisqwit.iki.fi/story/howto/openmp/#ParallelismConditionalityClauseIf 以了解如何基于索引进行并行化。但是鉴于代码 sn-ps 很难准确说出您想要做什么。

下一个最大的问题是您将有多个线程同时调用 .push_back。您需要预先分配和分配值。

我不确定您为什么要在 std::vector 中使用指针和新语法。通常使用带有 RAII 的向量并避免新/删除调用。

【讨论】:

我已经在问题中提供了我想要做的事情,两段不同的代码显示了我在哪里以及我试图在感知上实现什么。我会看一下链接,看看它是否能让我有更好的洞察力。此外,我使用新语法是因为向量位于一个方法中,该方法是对象的一部分,可能不会被删除,但可以通过重复数千到数十万次的方法进行编辑。因此,在没有新/删除语法的情况下,我会遇到建立向量的分配错误 主要是我对 sn-p 和 #pragma omp 并行部分感到困惑。从您发布的内容来看,您似乎正在尝试并行化各个 push_back 语句,但这是行不通的。但是,如果您有线程执行更多操作并预先分配缓冲区,您应该能够整体并行化您的代码,但如果不知道您发布的 sn-ps 之外发生了什么,就无法判断。 我正在尝试并行化推回和向量计算,所有信息都是已知的,并且读/写没有重叠。它只是不起作用吗?还是有它不起作用的原因?如果我必须预先分配然后分配值,那么鉴于我不知道这个矩阵中有多少列,那么尝试并行化这部分肯定没有意义?鉴于它是具有多个交互类的大型项目的一部分,因此无法在此论坛中向您展示此功能之外发生的事情。要显示的代码量很大。 迟到的回复,但根据你写的内容,你最好的选择是使用向量保留函数。 推回不可并行化,因为它每次超过保留的堆大小时都会重新分配向量的内存。每次调用内部指针都可能发生变化,因此每个线程最终可能会得到不同的内存指针,因为 stl 容器更改通常不是线程安全的。这也是您可能会在该代码中受到性能影响的原因,每个 push_back 都会导致向量重新分配。大块使用储备将有所帮助。至于并行化,如果您没有关于新的可能列的信息,我看不到一种简单的并行化方法。【参考方案2】:

在进行并行编程时,您必须注意“锁定数据”。此技术可防止两个(或更多)线程同时修改相同的数据,从而破坏它。

【讨论】:

并行 for 循环修改同一向量/矩阵中的数据对我有用。为什么要在此之外应用锁定? 我没有理论化,而是尝试设置锁,以检查锁定是否解决了崩溃。 会试一试。感谢您的帮助。

以上是关于使用并行编程 C++ 计算/访问向量的主要内容,如果未能解决你的问题,请参考以下文章

C++ 并行编程函数调用

C++ 并行编程中的“锁”难题

使用 c++ async 进行并行编程

虚幻4与现代C++:基于任务的并行编程与TaskGraph入门

虚幻4与现代C++:基于任务的并行编程与TaskGraph入门

C++11 并发编程基础:并发并行与C++多线程