我想使用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
答案 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系统上的错误共享和远程内存访问(但不会在最终还原阶段)。