2012-06-28 54 views
6

对于OpenMP 3.1,有可能有一个reduction子句min查找在阵列的最小元素,它的索引

double m; 
#pragma omp parallel for reduction(min:m) 
for (int i=0;i< n; i++){ 
    if (a[i]*2 < m) { 
    m = a[i] * 2; 
} 
return m; 

假设我还需要的最小元件的索引;有没有办法使用这个reduction条款?我相信替代方法是使用nowaitcritical手动编写缩减。

回答

5

假设我也需要最小元素的索引;有没有办法使用这个减少子句?

不幸的是,没有。 OpenMP可能的减少列表非常小。特别是,minmax是唯一的“高级”功能,它们不是可定制的。完全一样。

我不得不承认,我不喜欢OpenMP的减少方法,正因为它不能在一定程度上扩展,所以设计的只适用于特殊情况。当然,这些是有趣的特殊情况,但它仍然是一个根本不好的方法。

对于这样的操作,您需要通过将线程局部结果累加到线程局部变量并在末尾组合它们来实现自动缩减。

这样做的最简单的方法(实际上与OpenMP实现的减少方法非常接近)是为每个线程使用一个包含元素的数组,并使用omp_get_thread_num()来访问元素。但请注意,如果阵列中的元素共享缓存行,则会导致性能下降,原因是虚假共享。为了缓解这一点,垫阵列:

struct min_element_t { 
    double min_val; 
    size_t min_index; 
}; 

size_t const CACHE_LINE_SIZE = 1024; // for example. 
std::vector<min_element_t> mins(threadnum * CACHE_LINE_SIZE); 

#pragma omp parallel for 
for (int i = 0; i < n; ++i) { 
    size_t const index = omp_get_thread_num() * CACHE_LINE_SIZE; 
    // operate on mins[index] … 
} 
+0

我想你的意思是'omp_get_num_threads'? – user1071136

+0

@ user1071136不,我的意思是'omp_get_thread_num'。我们希望*索引*,而不是总数。至于'threadnum',这是一个占位符。您不能在这里使用'omp_get_num_threads',因为您不在并行区域内。相反,实际上应该将'numthread'作为后续parallel子句中的线程数。 –

+0

提及虚假分享。尽管如此,OpenMP减少子句是为了高效和易于实现而设计的,而不是为了可扩展性。 –