c - 使用 readdir 在 for 循环中并行递归
问题描述
我想并行化一个 C 程序,该程序使用 OpenMP 和 C 递归计算目录及其子目录的大小。
我的问题是,当我使用 进入目录并使用opendir
遍历子目录时,readdir
我只能一个接一个地访问它们,直到到达最后一个子目录。这一切都按顺序运作良好。
然而,当并行化程序时,我认为将子目录的数量分成两半(甚至更小的分区)并使用 OpenMp 任务通过子目录递归是有意义的。
显然,由于 for 循环的结构,我不能简单地将问题大小(= 子目录的数量)分成两半,并且这样的循环不能使用#pragma omp for
.
有人知道如何将此功能拆分为任务吗?任何帮助将不胜感激。
这是我的一些代码(我已经删除了我认为与这个问题无关的部分。)
int calculate_folder_size(const char *path) {
struct stat sb;
if (S_ISREG(sb.st_mode)) { // if it's a file, not a directory (base case)
return sb.st_size;
}
DIR *folder = opendir(path);
struct dirent *element;
size_t size = 4096;
for (element = readdir(folder); element != NULL; element = readdir(folder)) {
//(...)
if (element->d_type == DT_DIR) {
// recursive call of calculate_folder_size
size += calculate_folder_size(name);
} else {
//(...)
}
}
}
closedir(folder);
return size;
}
解决方案
您需要一个支持 OpenMP 任务的现代编译器,它将 Visual C++ 从等式中移除。如果您使用的是这样的编译器,您需要做的就是将递归调用转换calculate_folder_size()
为 OpenMP 任务:
int calculate_folder_size(const char *path) {
struct stat sb;
if (S_ISREG(sb.st_mode)) { // if it's a file, not a directory (base case)
return sb.st_size;
}
DIR *folder = opendir(path);
struct dirent *element;
size_t size = 4096;
for (element = readdir(folder); element != NULL; element = readdir(folder)) {
//(...)
if (element->d_type == DT_DIR) {
// Make sure the task receives a copy of the path
char *priv_name = strdup(name); // (1)
// recursive call of calculate_folder_size
// (2)
#pragma omp task shared(size) firstprivate(priv_name)
{
// (3)
#pragma omp atomic update
size += calculate_folder_size(priv_name);
free(priv_name); // (4)
}
} else {
//(...)
}
}
// (5)
#pragma omp taskwait
closedir(folder);
return size;
}
这里的重要部分是:
您需要向任务传递一个名称参数,该名称参数将一直存在并保留其值,直到任务被执行,这可能是将来的任何时间。因此,您需要制作 的副本
name
,例如,使用strdup(3)
.任务应该记住 的当前值,
priv_name
因为它将在循环的下一次迭代中发生变化。因此,firstprivate
治疗priv_name
。它还需要能够size
在父上下文中进行修改,因此shared
需要它。由于所有任务都在更新
size
父作用域中的同一个变量,因此需要使用atomic update
.不再需要私有名称,必须对其进行处置。
父任务应先等待所有子任务完成后再返回
size
。
必须从并行区域内调用此函数才能并行完成其工作:
int size;
#pragma omp parallel
#pragma omp single
size = calculate_folder_size("/some/path");
限制事物仍然并行运行的并行深度可能是一个好主意。我把它留给你弄清楚如何:)
推荐阅读
- hibernate - JPA继承设计问题
- node.js - 如何在不执行 Express Js Promise 中的下一条语句的情况下从 .then() 中逃脱?
- r - 在 R 版本 4.0 中加载 ggplot2 的问题
- python - 安装 PyQt5 后无法启动 Spyder
- mysql - Laravel Eloquent 试图检索表中具有相同外键的所有答案
- python-3.x - 无法使用烧瓶 wsgi 渲染模板
- amazon-ec2 - 试图获取 ec2 图像列表,包括 blockDeviceMappings.snpshotID
- android - Android Studio 中的哨兵上传失败
- javascript - 将具有 onclick 功能的动态按钮添加到单元格
- java - UUID 的紧凑替代品作为相关 ID