You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

readdir_r弃用的性能影响及FUSE文件系统多线程同步疑问

关于FUSE文件系统中readdir线程安全与性能的解惑

我之前做叠加型FUSE文件系统的时候也踩过这个readdir的坑,刚好帮你理清楚这些问题:

首先明确readdir的线程安全边界

POSIX标准说得很清楚:readdir() 针对不同的目录流(也就是不同的DIR*指针)是线程安全的,但如果多个线程同时操作同一个DIR*,那不管是单个readdir()调用,还是整个读取目录的流程,都是完全不安全的。

为什么?因为DIR结构体内部藏着当前读取的偏移位置、临时缓冲区这些状态,readdir()每次调用都会修改这些状态。多线程并发操作同一个DIR*的话,轻则导致返回的目录条目重复、缺失,重则直接让程序崩溃——毕竟你没法预料两个线程同时修改同一个内存区域会搞出什么乱子。

同步范围该怎么选?

你的纠结很正常,但其实最优解根本不是在“单个调用加锁”和“整个流程加锁”里选:

  • 如果你给单个readdir()调用加锁,看起来粒度细,但实际没用——就算每个调用都加锁,多个线程共享同一个DIR*的话,读取的条目会被打乱(比如线程A读了2个条目,线程B插进来读3个,再换回A继续读),这完全不符合用户进程对“读取整个目录”的预期,而且锁竞争的开销也没少多少。
  • 如果你把整个读取流程放进临界区,那所有读取该目录的请求都会被串行化,高并发场景下性能会崩得很惨。

真正的最优方案:不要共享DIR*

每个需要读取目录的线程/请求,都独立调用opendir()打开自己的DIR*,读完后立刻closedir()关闭。这样每个线程都有自己的目录流,完全不需要加锁,天然线程安全。

你可能担心重复打开目录的性能开销?其实大可不必——Linux内核的目录缓存(dentry cache + page cache)会把目录内容存在内存里,只要不是第一次读取,后续的opendir()和readdir()基本都是从内存里拿数据,磁盘IO开销可以忽略不计。反而共享DIR*加锁的方案,在高并发下的锁竞争才是真正的性能杀手。

关于Linux内核的单目录并行读取限制

内核根本没有这种限制!相反,内核的设计就是支持多进程/线程并行读取同一个目录的——每个进程/线程打开目录时,内核都会给它分配独立的file结构体,各自维护自己的读取位置,互相完全不干扰。只要你的FUSE文件系统内部为每个readdir请求独立处理目录读取,就能充分利用内核的并行能力,不会有瓶颈。

最后说下readdir_r的弃用

readdir_r被弃用不是因为线程安全问题,而是它本身的设计缺陷:比如你得自己分配缓冲区,但很难确定缓冲区的大小,容易导致溢出或者浪费内存。现在推荐的替代方案就是用普通的readdir(),只要保证每个线程用自己独立的DIR*,就完全是线程安全的,比readdir_r好用多了。

内容的提问来源于stack exchange,提问作者Lapsio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 15:32:49