C与Python通过FIFO进行IPC时双进程阻塞或触发BlockingIOError问题求助
问题根因分析
- FIFO打开模式错误:你在C和Python侧都使用
O_RDWR模式打开FIFO,违背了FIFO半双工的设计逻辑。FIFO标准用法是单侧只读、另一侧只写,读写模式打开时进程会同时持有读、写两端的引用,导致内核无法触发正常的管道唤醒、EOF检测逻辑,就算有写入数据也可能因为缓存、引用计数异常导致读操作永久阻塞。 - FIFO打开顺序不匹配:你当前C侧仅打开了
/tmp/Pipe_01,没有提前打开/tmp/Pipe_02的读端,虽然用O_RDWR绕过了打开阶段的阻塞,但后续读写逻辑仍然因为端引用异常卡住。 - 子进程文件描述符继承问题:C进程fork出子进程后,父进程打开的所有文件描述符会默认被子进程继承,如果你打开FIFO的fd没有设置
FD_CLOEXEC标志,execv启动Python后这些fd仍会保留,导致FIFO的端引用计数混乱,永远不会触发可读/可写事件。
解决方案
1. 调整C侧逻辑
- 两个FIFO严格按单向模式打开:
/tmp/Pipe_01是C写、Python读,C侧用O_WRONLY模式打开/tmp/Pipe_02是Python写、C读,C侧用O_RDONLY模式打开
- 打开FIFO时添加
O_CLOEXEC标志,避免子进程继承fd:// 打开FIFO示例代码 int fd_pipe1 = open("/tmp/Pipe_01", O_WRONLY | O_CLOEXEC); int fd_pipe2 = open("/tmp/Pipe_02", O_RDONLY | O_CLOEXEC); - 必须先完成两个FIFO的打开操作,再执行fork+execv启动Python进程;写入数据后调用
fsync(fd_pipe1)主动刷入内核缓存,确保Python侧可以立刻读到数据。
2. 调整Python侧逻辑
严格按单向模式阻塞打开FIFO,不需要使用O_RDWR或者非阻塞标志:
#!/usr/bin/python3 import os # Pipe_01为Python读端,使用只读模式打开 pr = os.open('/tmp/Pipe_01', os.O_RDONLY) print("Read Opened") # Pipe_02为Python写端,使用只写模式打开 pw = os.open('/tmp/Pipe_02', os.O_WRONLY) print("Write Opened") while True: v = os.read(pr, 3) # 读返回空字节代表C侧写端已关闭,可直接退出循环 if not v: break print("Python read") print(v) # 向C侧返回数据时,写完可调用os.fsync(pw)刷缓存 # os.write(pw, 返回给C的数据)
可选:非阻塞读适配
如果确实需要非阻塞读避免进程卡死,捕获BlockingIOError异常处理即可:
#!/usr/bin/python3 import os import errno pr = os.open('/tmp/Pipe_01', os.O_RDONLY | os.O_NONBLOCK) pw = os.open('/tmp/Pipe_02', os.O_WRONLY) while True: try: v = os.read(pr, 3) if not v: break print(v) # 处理返回逻辑 except BlockingIOError as e: if e.errno == errno.EAGAIN: # 无数据时可以休眠或执行其他任务 os.sleep(0.01) continue # 其他异常直接抛出 raise
内容的提问来源于stack exchange,提问作者RTC222
相关产品推荐
相关产品推荐

