在不使用临界区的情况下,与OpenMP并行填充直方图(数组缩减)

时间:2013-05-28 10:02:42

标签: openmp histogram

我想使用OpenMP并行填充直方图。我在C / C ++中使用OpenMP提出了两种不同的方法。

第一个方法proccess_data_v1为每个线程创建一个私有直方图变量hist_private,并行填充它们,然后将私有直方图加到{{1}中的共享直方图hist中}} 部分。

第二种方法critical生成一个直方图的共享数组,其数组大小等于线程数,并行填充此数组,然后并行汇总共享直方图proccess_data_v2

第二种方法似乎优于我,因为它避免了临界区并且并行地对直方图求和。但是,它需要知道线程数并调用hist。我一般都试图避免这种情况。有没有更好的方法来执行第二种方法而不引用线程数并使用大小等于线程数的共享数组?

omp_get_thread_num()

修改 根据@HristoIliev的建议,我创建了一个名为void proccess_data_v1(float *data, int *hist, const int n, const int nbins, float max) { #pragma omp parallel { int *hist_private = new int[nbins]; for(int i=0; i<nbins; i++) hist_private[i] = 0; #pragma omp for nowait for(int i=0; i<n; i++) { float x = reconstruct_data(data[i]); fill_hist(hist_private, nbins, max, x); } #pragma omp critical { for(int i=0; i<nbins; i++) { hist[i] += hist_private[i]; } } delete[] hist_private; } } void proccess_data_v2(float *data, int *hist, const int n, const int nbins, float max) { const int nthreads = 8; omp_set_num_threads(nthreads); int *hista = new int[nbins*nthreads]; #pragma omp parallel { const int ithread = omp_get_thread_num(); for(int i=0; i<nbins; i++) hista[nbins*ithread+i] = 0; #pragma omp for for(int i=0; i<n; i++) { float x = reconstruct_data(data[i]); fill_hist(&hista[nbins*ithread], nbins, max, x); } #pragma omp for for(int i=0; i<nbins; i++) { for(int t=0; t<nthreads; t++) { hist[i] += hista[nbins*t + i]; } } } delete[] hista; }

的改进方法
process_data_v3

1 个答案:

答案 0 :(得分:4)

你可以在并行区域内分配大数组,在那里你可以查询实际使用的线程数:

int *hista;
#pragma omp parallel 
{
    const int nthreads = omp_get_num_threads();
    const int ithread = omp_get_thread_num();

    #pragma omp single
    hista = new int[nbins*nthreads];

    ...
}
delete[] hista;

为了获得更好的性能,我建议你将hista中每个线程块的大小舍入到系统内存页面大小的倍数,即使这可能会在不同的部分直方图之间留下漏洞。通过这种方式,您可以防止NUMA系统上的错误共享和远程内存访问(但不会在最终还原阶段)。