为什么在没有编写器的命名管道上选择无限期阻塞?

时间:2017-06-18 18:53:40

标签: c++ linux select posix nonblocking

我在read_fds中使用单个命名管道fd调用select。此命名管道没有编写器,只能以非阻塞,只读模式打开。我希望select返回命名管道fd标记为准备读取,并且尝试从管道读取返回0:

从阅读的联机帮助页:

  

尝试从空管道或FIFO读取时:

     
      
  • 如果没有进程打开管道进行写入,read()将返回0到>表示文件结束。
  •   

但是,无限期地选择块。为什么会这样?

{{1}}

1 个答案:

答案 0 :(得分:4)

来自select的POSIX文档:

  

当对具有O_NONBLOCK clear的输入函数的调用不会阻塞时,该函数将成功传输数据时,应认为描述符已准备好读取。 (该函数可能返回数据,文件结束指示或除了表示被阻止的错误之外的错误,并且在每种情况下,描述符都应被视为已准备好进行读取。

     

...

     

如果所选描述符都没有为请求的操作做好准备,则pselect()或select()函数将阻塞,直到至少一个请求的操作准备就绪,直到超时发生,或直到被信号打断。

pipe(7)联机帮助页(它是FIFO的基础对象):

  

如果引用管道的写入端的所有文件描述符都已关闭,则尝试从管道读取(2)将看到文件结束(read(2)将返回0)。

注意现在完成时的用法!这意味着FIFO必须在 fiorst 两侧打开,在编写者端(为您的应用程序)关闭以生成EOF条件。

所以,除非作者最终关闭了fifo,为什么select会返回? (fifo-)文件本身的设置无关紧要:当使用最有效的方法一次读取多个字节时,它会在双方打开之间引入竞争条件。这是例如正常的方式。命令管道:启动读取器进程,然后启动编写器(使用命名管道时通常是完全不相关的程序)。

如果您希望select提前返回,请使用timeout参数。但通常情况下,使用单独的线程可以通过信号终止(有关更多信息,请参阅select手册页。)

作为旁注:关于Linux / POSIX的一个好处是,使用FIFO或文件或麦克风驱动程序并不重要。