有可能你没有注意打开的返回码.如果打开FIFO进行写入和非阻塞,则有两种可能的结果.
>如果已有读卡器,则打开将立即成功返回.
>如果没有管道读取器,则打开将失败并显示errno = ENXIO.
以下程序演示.
#include
#include
#include
#include
#include
#include
#define SERVFIFO "/tmp/server.fifo"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
void syserr(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char** argv)
{
umask(0);
if (mkfifo(SERVFIFO,FILE_MODE) < 0 && errno != EEXIST)
syserr("mkfifo");
// try to open for write with no readers
int fdw = open(SERVFIFO,O_WRONLY | O_NONBLOCK);
if (fdw == -1)
perror("non-blocking open for write with no readers Failed");
// create a reader - the process itself - non-blocking
int fdr = open(SERVFIFO,O_RDONLY | O_NONBLOCK);
if (fdr == -1)
syserr("non-blocking open for read no writers Failed");
// try again to open for write but this time with a reader
fdw = open(SERVFIFO,O_WRONLY | O_NONBLOCK);
if (fdw == -1)
syserr("non-blocking open with readers Failed");
printf("non-blocking open for write succeeded\n");
close(fdw);
close(fdr);
unlink(SERVFIFO);
}
也就是说,open没有阻塞就失败的事实并不是那么有用.关于你唯一能做的就是不断尝试打开,直到你成功,这种轮询可能是浪费,而在长期运行程序的情况下等待间歇性读者是有点荒谬的.
一种解决方案是上面使用的 – 打开FIFO以便自己阅读 – 但这有其自身的问题.
>如果在select语句中使用FIFO写入fd,它总是可写的……直到它不可写.也就是说,因为您也是自己的读取器,所以FIFO写入将成功,直到您使用PIPE_BUF字节填充FIFO缓冲区.之后,FIFO将无法写入,并且您的写入将在EAGAIN中失败,直到合法读取器(即非您自己)出现,打开以进行读取,并开始耗尽缓冲区.
>通过打开自己的FIFO进行读写,当合法用户关闭FIFO时,您将看不到EOF.由于您只关心写作,这对您来说可能不是问题.
我从未尝试过的另一种可能的解决方案是在FIFO上使用inotify.您可以在选择中监视inotify文件描述符,并确定何时有人打开FIFO.然后你知道你可以安全地开始写作.您可能希望屏蔽FIFO上的打开权限,以便您可以成为唯一的编写者,如果可能的话,您的应用程序.
对于这些时髦的语义,FIFO应该被重命名为PITA.如果你能做出改变,这就是为什么Unix众神赋予我们凡人的域名套接字.