如何区分 fifo 可打开内容和可读内容?

How to distinguish fifo openable vs readable content?

我对 Linux 上的 fifo 有点陌生,对 select() 的经验也有限。

learned 在 FIFO 的读取端调用 open() 将阻塞,直到写入端完成管道。

可以用O_NONBLOCK打开fifo的读端,以免阻塞在open()。然后,您可以 select() 在 readfds 中使用 fifo 的文件描述符,以便了解文件何时可打开 - 是吗?

虽然我现在很困惑:在知道文件是可打开的之后,我随后想知道 fifo 有可读的内容,即我想知道 read()在 fifo 文件描述符上不会阻塞。为此,我会考虑 select() 使用 readfds 中的 fifo 文件描述符 - 但这似乎与使用 select() 来了解文件是否可打开相冲突。

所以我想总结一下我的问题:我如何使用 select() 知道 1) fifo 读取端的 open() 何时不会阻塞,以及 2) read() 在 fifo 上不会阻塞?

我假设 select() 在读取端解锁以指示 fifo 是可打开的,这似乎是不正确的。看起来 select() 只有当 fifo 中有数据要读取时才会在读取端解除阻塞。

这个测试代码证明了我的观察:按原样,select() 超时;取消注释单个注释行,select() 解除对 fifo 文件描述符的阻塞。

#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <ctime>

#define FIFO "/tmp/foo"

void* sr1( void* arg )
{
  mkfifo( FIFO, 0777 );
  sleep( 3 );
  int fd = open ( FIFO, O_WRONLY );
  //write( fd, "a", 1 );
  std::cout << "t1 opened " << fd << std::endl;
  sleep( 3 );
  close( fd );
  std::cout << "t1 closed " << fd << std::endl;
  return NULL;
}

void* sr2( void* arg )
{
  int fd = open( FIFO, O_RDONLY | O_NONBLOCK );
  std::cout << "t2 opened " << fd << std::endl;
  fd_set readfds;
  FD_ZERO( &readfds );
  FD_SET( fd, &readfds );
  struct timeval ts = { 5, 0 };
  std::cout << "t2 waiting now" << std::endl;
  select( fd + 1, &readfds, NULL, NULL, &ts );
  if ( FD_ISSET( fd, &readfds ) )
  {
    std::cout << "t2 " << fd << " set so select() unblocked" << std::endl;
  }
  else
  {
    std::cout << "t2 " << " select() unblocked at timeout" << std::endl;
  }
  close( fd );
  std::cout << "t2 closed " << fd << std::endl;
  return NULL;
}

int main( int argc, char* argv[] )
{
  pthread_t t1;
  pthread_t t2;

  pthread_create( &t1, NULL, sr1, NULL );
  pthread_create( &t2, NULL, sr2, NULL );

  pthread_join( t1, NULL );
  pthread_join( t2, NULL );
}