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

3

我有一个矩阵:

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'是一个整数值。在某个点上,我应用了一个函数,其具体如下:

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”仅包含push backs时,这段代码仍然会崩溃。想知道是否有人知道为什么会发生这种情况?

我还在尝试进一步了解并行编程,以知道何时/何时不能在给定的函数中使用它,因为有时使某些方面并行化导致代码出现未知原因的崩溃。如果有人能提供帮助我解决这个问题的资源,那就太好了。


竞态条件在这里。 - apple apple
即使我只是在矩阵的两个不同位置应用push_backs @appleapple,也会出现这种情况。 - mwtmurphy
2个回答

0
首先,#pragma omp parallel 只会在该点生成一堆线程,在作用域部分执行相同的操作,它不会为每个线程分配唯一的 j 或 i。您可能需要查看 http://bisqwit.iki.fi/story/howto/openmp/#ParallelismConditionalityClauseIf 以了解如何基于索引并行化。但是,鉴于代码片段,很难确定您想要做什么。
接下来最大的问题是,您将有多个线程同时调用 .push_back。您需要预分配和分配值。
我不确定为什么您要使用指针和 std::vector 的新语法。通常人们使用 RAII 的 vector 并避免 new/delete 调用。

我在问题中提供了我想做的事情,并展示了两个不同的代码片段,以显示我现在的状态和我尝试感知实现什么。我会看一下链接,看看它是否能给我更好的见解。此外,我使用新语法,因为向量所在的方法是一个对象的一部分,该对象可能不会被删除,但可以通过重复执行该方法进行编辑,重复执行次数可能达到几千到几十万次。因此,在没有使用new/delete语法建立向量时,我会遇到分配错误。 - mwtmurphy
主要是我对带有#pragma omp parallel部分的代码片段感到困惑。从您发布的内容来看,似乎您正在尝试并行化单个push_back语句,这是行不通的。但是,如果您在整体上使线程执行更多任务并预先分配缓冲区,您应该能够使您的代码并行化。不过,如果不了解您发布的代码片段之外发生的事情,很难判断是否可行。 - aah
我正在尝试并行化push backs和向量计算,所有信息都已知,并且读/写没有重叠。它为什么不能正常工作?还是有原因导致它不能正常工作?如果我必须预先分配空间然后再赋值,那么考虑到我不知道这个矩阵中会有多少列,肯定没有必要尝试并行化这部分吧?在这个函数之外展示正在发生的事情在这个论坛上是不可能的,因为它是一个涉及多个交互类的大型项目的一部分。展示代码将是一个巨大的代码块。 - mwtmurphy
回复晚了,但根据您所写的内容,您立即获得性能提升的最佳选择是使用向量保留函数。 - aah
推回操作不可并行化,因为每次超过保留堆大小时都会重新分配向量的内存。每次调用时内部指针可能会改变,因此每个线程可能会得到不同的内存指针,因为STL容器更改通常不是线程安全的。这也是您在该代码中可能遇到性能问题的原因,每次push_back都会导致向量重新分配。使用大块的reserve将有所帮助。至于并行化,如果您没有关于新可能列的信息,我看不到简单的并行化方法。 - aah

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

并行的for循环在修改同一向量/矩阵中的数据时对我有效。为什么要在此之外应用锁定? - mwtmurphy
不要只停留在理论上,我会尝试设置锁定来检查锁定是否解决了崩溃问题。 - Ripi2
会尝试一下。感谢帮助。 - mwtmurphy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接