以下函数从循环中的文件中读取数据,并一次处理每个加载的块。为了加快这个过程,我想在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
序列化访问权限缓冲区。我对吗?你们看到我的代码存在问题吗?如何增强此代码?
非常感谢。
答案 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
,那么这些都是很好的解决方案。