使用openmp时可能出现竞争条件问题

时间:2018-04-16 17:18:28

标签: c parallel-processing openmp

以下函数从循环中的文件中读取数据,并一次处理每个加载的块。为了加快这个过程,我想在for循环中使用openmp,以便这个作业在线程之间划分如下:

void read_process(FILE *fp_read, double *centroids, int total) {

    int i, j, c, dim = 16, chunk_size = 10000, num_itr;
    double *buffer = calloc(total * dim, sizeof(double));
    num_itr = total / chunk_size;
    for (c = 0; c < total; ++c) {
        fread(buffer, sizeof(double), chunk_size * dim, fp_read);
#pragma omp parallel private(i, j)
        {
            #pragma omp for
            for (i = 0; i < chunk_size; i++) {
                for (j = 0; j < dim; j++) {
                    #pragma omp atomic update
                    centroids[j] += buffer[i * dim + j];
                }
            }
        }
    }

    free(buffer);
    fclose(fp_read);
}

不使用openmp,我的代码运行正常。但是,添加#pragma部分会导致代码停止并在终端中显示单词Hangup,而无需进一步说明其被挂起的内容。 StackOverflow中的一些人回答了与此错误消息相关的其他问题,可能是因为race condition,但我认为不会出现这种情况,因为我使用atomic序列化访问权限缓冲区。我对吗?你们看到我的代码存在问题吗?如何增强此代码?

非常感谢。

1 个答案:

答案 0 :(得分:0)

你想要做的是array reduction。如果您有一个支持OpenMP 4.5的编译器,那么您不需要更改序列代码。你可以做到

EnqueueAt

否则你可以手动进行阵列缩减。这是一个解决方案

#pragma omp parallel for private (j) reduction(+:centroids[:dim])
for(i=0; i <chunck_size; i++) {
  for(j=0; j < dim; j++) {
    centroids[j] += buffer[i*dim +j];
  }
}  

当前解决方案导致大量错误共享,因为每个线程都在写入同一缓存行。上述两种解决方案都通过为每个线程创建#pragma omp parallel private(j) { double tmp[dim] = {0}; #pragma omp for for(i=0; i < chunck_size; i++) { for(j=0; j < dim; j++) { tmp[j] += buffer[i*dim +j]; } } #pragma omp critical for(int i=0; i < dim; i++) centroids[i] += tmp[i]; } 的私有版本来解决此问题。

只要centroid,那么这些都是很好的解决方案。