如何判断FIFO写端对应读端是否关闭?如何避免写阻塞?
FIFO相关问题解答
问题1:如何判断打开用于写入的FIFO描述符对应的读端是否存在?
咱们没有直接的系统调用能一键查询这个状态,但可以通过几个间接方法来判断:
非阻塞写测试法:
- 先保存原有的文件描述符标志,再用
fcntl(fd, F_SETFL, O_NONBLOCK)把写端设为非阻塞模式(用完记得恢复原标志,避免影响后续操作); - 尝试写入一个极小的测试数据(比如一个字节的占位符):
- 如果
write()返回-1且errno == ENXIO,说明当前没有任何读端打开; - 如果返回
-1且errno == EAGAIN,说明读端存在,但FIFO写缓冲区已满,暂时没法写入; - 如果写入成功(返回值≥0),说明读端正常在线。
要注意:别用write(fd, NULL, 0)来测试,写入0字节的操作不管读端是否存在都会返回成功,完全起不到判断作用。
- 如果
- 先保存原有的文件描述符标志,再用
借助SIGPIPE信号(事后判断):
这是在实际写入时触发的判断——如果所有读端都关闭了,写操作会触发SIGPIPE信号(默认会直接终止你的进程)。如果你提前用signal(SIGPIPE, SIG_IGN)忽略这个信号,那么write()会返回-1,同时errno被设为EPIPE,这时候你就能明确知道读端已经关闭了。但这是事后检测,没法提前预判。
问题2:读端关闭后写端如何知晓?以及如何避免写操作阻塞?
读端关闭的检测方式
当FIFO的所有读端都关闭后,写端会有两种明显的反馈:
- 默认行为:你的进程会收到
SIGPIPE信号,直接终止; - 提前忽略
SIGPIPE:如果你在代码开头加上signal(SIGPIPE, SIG_IGN),那么后续的write()操作会返回-1,同时errno等于EPIPE,这时候你就能在代码里处理读端关闭的逻辑,而不会直接挂掉进程。
另外,你也可以用poll/select来提前监控:当读端关闭时,写端的文件描述符会触发POLLHUP事件,这样你在尝试写入前就能知道读端已经下线了。
避免写阻塞的方案
如果你不想让写端因为没有读端而阻塞(不管是打开FIFO的时候,还是写入数据的时候),可以试试这两个方法:
非阻塞模式打开FIFO:
打开写端时加上O_NONBLOCK标志:int fd = open("your_fifo_path", O_WRONLY | O_NONBLOCK);- 如果此时没有读端打开,
open()会立即返回-1,errno为ENXIO; - 你可以写个循环,每隔一段时间尝试
open一次,直到成功(说明有读端连上了),这样就不会卡在open调用上。
- 如果此时没有读端打开,
用
poll监控可写状态:
当你已经成功打开写端后,可以用poll来监控文件描述符的状态,避免写入阻塞:struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; // 等待1秒,超时可以自己调整 int ret = poll(&pfd, 1, 1000); if (ret > 0) { if (pfd.revents & POLLOUT) { // 可以安全写入,不会阻塞 write(fd, your_data, data_len); } else if (pfd.revents & POLLHUP) { // 读端已经关闭,这里做清理工作 close(fd); // 可以尝试重新打开FIFO } }
内容的提问来源于stack exchange,提问作者Omer Anisfeld
相关产品推荐
相关产品推荐

