在 CentOS(Linux) 上,readdir()(以及 opendir()/readdir_r())本身是 同步、可能阻塞 的系统调用,尤其在以下情况会卡住:
下面按 实用程度 给你几种避免或降低阻塞的方法。
这是 最简单、最稳妥 的方式。
#include <pthread.h>
#include <dirent.h>
void *scan_dir(void *arg) {
DIR *dir = opendir((char *)arg);
if (!dir) return NULL;
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
// 处理文件
}
closedir(dir);
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, scan_dir, "/data/big_dir");
pthread_detach(tid);
}
✅ 主线程不阻塞
✅ 代码简单
✅ CentOS 默认支持
readdir_r(线程安全,但不解决阻塞)struct dirent entry;
struct dirent *result;
while (readdir_r(dir, &entry, &result) == 0 && result) {
// 处理
}
⚠️ 只是线程安全,不避免阻塞
getdents() + 非阻塞思路(进阶)readdir 本质调用 getdents64()。
getdents64⚠️ 复杂,一般不推荐,除非你写底层工具
inotify(不是扫描,是监听)如果你是“想知道目录变化”,而不是“遍历”:
inotifywait -m /path
✅ 完全不阻塞
❌ 不能替代 readdir
alarmalarm(5); // 5 秒超时
readdir(dir);
⚠️ 只能用于主线程,且不可重入
waitpid 超时(推荐)pid_t pid = fork();
if (pid == 0) {
// 子进程 readdir
exit(0);
}
int status;
waitpid(pid, &status, WNOHANG);
如果是:
df -h /path
# nfs / cifs / fuse
✅ 强烈建议:
soft 挂载timeo=, retry=mount -o soft,timeo=10,retry=2 nfs:/data /mnt
否则 readdir 可能 卡几分钟
| 场景 | 建议 |
|---|---|
| 普通目录 | 线程 |
| 大目录 | 线程 + 分批 |
| NFS | 线程 + soft 挂载 |
| 不能阻塞主线程 | 线程 / 子进程 |
| 只关心变化 | inotify |
如果你愿意,可以告诉我:
我可以给你 可直接用的代码模板。