Linux 命名管道 FIFO
命名管道(FIFO,First In First Out)是 Linux 中一种特殊的文件类型,让不同进程之间可以通过“管道”传递数据。跟普通的管道(|)不同,命名管道是个实际存在于文件系统中的文件,可以让不相关的进程通信。
1. 什么是命名管道?
命名管道(FIFO)就像一个有名字的管道文件,存在于文件系统里,任何进程都可以通过它读写数据。普通管道(|)只能在有亲缘关系的进程(比如父子进程)或通过 stdout/stdin 连接的命令中使用,而命名管道允许任意进程通过文件路径访问它。
- 特点:FIFO 是“先进先出”的,数据按写入顺序被读取。
- 文件类型:在文件系统里,FIFO 文件的类型标记为
p(pipe)。
你可以用 ls -l 看到 FIFO 文件,比如:
ls -l myfifo
输出可能是:
prw-r--r-- 1 user user 0 Aug 9 20:00 myfifo
这里的 p 表示它是个命名管道。
2. 创建命名管道
可以用 mkfifo 命令创建命名管道。基本语法是:
mkfifo myfifo
这会在当前目录创建一个名叫 myfifo 的命名管道文件。
- 检查创建结果:
ls -l myfifo
会看到类型为 p 的文件。
也可以用 mknod 命令(稍微老派,但也常用):
mknod myfifo p
- 参数说明:
p指定创建的是管道文件。 - 权限:FIFO 文件跟普通文件一样有权限设置,创建时可以用
chmod修改:
mkfifo myfifo
chmod 666 myfifo
这让所有用户都能读写 myfifo。
3. 向命名管道写入数据
命名管道可以像文件一样写入数据,但需要有进程在另一端读取,否则写入会阻塞(卡住)。可以用重定向或命令向 FIFO 写入。
比如,打开一个终端,写入数据:
echo "Hello, FIFO!" > myfifo
这行命令会把 "Hello, FIFO!" 写入 myfifo,但会卡住,直到有进程从 myfifo 读取数据。
可以用其他命令写入,比如:
cat file.txt > myfifo
这会把 file.txt 的内容写入 myfifo。
4. 从命名管道读取数据
读取 FIFO 也像操作文件,用重定向或命令。打开另一个终端,读取数据:
cat < myfifo
运行后,终端会显示:
Hello, FIFO!
一旦数据被读取,写入端(echo)的阻塞会解除,两个进程就完成了通信。
可以用其他命令读取,比如:
grep "Hello" < myfifo
这会从 myfifo 读取数据,过滤包含 “Hello” 的行。
5. 命名管道的阻塞行为
FIFO 有一个重要特点:读写阻塞。
- 如果没有进程读取,写入会卡住。
- 如果没有进程写入,读取会卡住。
这保证了数据传递的同步性。比如:
mkfifo myfifo
echo "Test data" > myfifo
运行后,echo 会卡住,直到你在另一个终端运行:
cat < myfifo
cat 读取数据后,echo 才会继续执行。
如果不想阻塞,可以用非阻塞模式(需要 open 系统调用,bash 里稍微复杂,常用工具如 cat 默认阻塞)。
6. 多进程通信
命名管道的强大之处在于让不相关的进程通信。比如,一个进程写日志,另一个进程实时处理:
终端 1(写入):
tail -f /var/log/syslog > myfifo
终端 2(读取并处理):
grep "error" < myfifo
tail -f持续把系统日志写入myfifo。grep从myfifo读取并过滤出包含 “error” 的行。
这样就实现了一个简单的实时日志监控。
7. 删除命名管道
用完 FIFO 后,可以像删除普通文件一样用 rm 删掉:
rm myfifo
删除后,FIFO 文件消失,相关进程的读写会停止(可能报错,视情况而定)。
8. 实际例子:综合运用
来个综合例子,模拟两个进程通信:
终端 1(生产数据):
mkfifo myfifo
while true; do
echo "Data at $(date)" >> myfifo
sleep 1
done
- 创建
myfifo。 - 循环每秒向
myfifo写入当前时间。
终端 2(处理数据):
cat < myfifo | grep "2025"
- 从
myfifo读取数据。 - 过滤包含 “2025” 的行(假设是 2025 年)。
终端 2 会持续显示类似:
Data at Sat Aug 9 20:00:01 HKT 2025