我试着写这个代码
float* theArray; // the array to find the minimum value
int index, i;
float thisValue, min;
index = 0;
min = theArray[0];
#pragma omp parallel for reduction(min:min_dist)
for (i=1; i<size; i++) {
thisValue = theArray[i];
if (thisValue < min)
{ /* find the min and its array index */
min = thisValue;
index = i;
}
}
return(index);
然而,这一个没有输出正确的答案。似乎最小值是可以的,但正确的索引已被线程破坏。
我也尝试了一些在互联网上和这里提供的方法(使用parallel for for外部循环,使用critical进行最终比较),但这会导致速度下降而不是加速。
我应该怎么做才能使最小值和它的索引都正确呢?谢谢!
4条答案
按热度按时间uqdfh47h1#
我不知道有什么优雅的方法想要做一个最小值缩减并保存一个索引,我是通过找到每个线程的局部最小值和索引,然后在临界区找到全局最小值和索引来实现的。
在OpenMP 4.0中,可以使用用户定义的约简。用户定义的最小约简可以如下定义
然后可以像这样进行归约
这适用于C和C++。用户定义的约简除了简化代码外还有其他优势。有多种算法可用于约简。例如,合并可以在
O(number of threads)
或O(Log(number of threads)
中完成。我给出的第一个解决方案在O(number of threads)
中完成此操作,但使用用户定义的约简时,让OpenMP来选择算法。elcex8rz2#
这可以通过创建custom reduction来完成,而无需任何对
critical
或atomic
节的并行化破坏。基本上,定义一个同时存储索引和值的对象,然后创建一个函数,仅根据值而不是索引对其中两个对象进行排序。将索引和值存储在一起的对象:
您可以通过访问
first
属性来访问索引,通过访问second
属性来访问值,即:定义一个函数以对两个
IndexValuePair
对象进行排序:然后,按照OpenMP documentation中的指导原则构建自定义缩减:
在本例中,我选择将索引初始化为0,将值初始化为1000。值应该初始化为大于您期望排序的最大值的某个数字。
最后,用parallel for循环组合所有这些片段!
k2fxgqgv3#
因为你不仅要找到最小值(
reduction(min:___)
),但同时保留索引,则需要使检查成为关键检查。这会显著降低循环速度(如报告所述)一般而言,请确保有足够的工作量,这样您就不会遇到this问题中的开销。另一种方法是让每个线程找到最小值,并将其s索引并将它们保存到一个唯一的变量中,然后让主线程对它们进行最后的检查,如下面的程序所示。请注意,如果优化处于打开状态,并且循环中没有其他操作,那么串行版本似乎仍然是王者。如果优化处于关闭状态,那么OMP将占据上风。
你写了
reduction(min:min_dist)
,然后用min代替min_dist
。cwtwac6a4#
实际上,我们可以使用
omp critical
指令,让一个线程同时运行临界区中的代码,这样只有一个线程可以运行它,并且索引值不会被其他线程破坏。关于omp关键指令:
omp critical指令标识一段代码,一次必须由一个线程执行。
此代码可解决您的问题: