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