在 linux 中无法使用 fcntl 切换到阻止模式

cannot switch to blocking mode using fcntl in linux

我有一个示例程序:

int main()
{
   const char* fn = "/tmp/tmpfifo";
   int i = mkfifo(fn, 0666);
   int fd = open(fn, O_RDONLY | O_NONBLOCK);
   int flags = fcntl(fd, F_GETFL);
   flags &= ~O_NONBLOCK;
   fcntl(fd, F_SETFL, flags);

   char buf[1024];
   int rd= read(fd, buf, 100);
   cout << rd << endl;
   remove(fn);
   return 0;
}

似乎在从文件描述符中删除非阻塞标志后,read 调用应该阻塞,直到有内容写入 FIFO,但我的程序总是在没有阻塞的情况下运行并且 rd=0结果。你能解释一下这种行为吗?谢谢!

奇怪!我尝试了一个代码,它在没有 O_NONBLOCK 的情况下打开文件,然后分 3 个阶段进行。尽管 O_NONBLOCK 标志结果重置,但第 3 阶段没有正确运行!

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main()
{
   char buf[1024];
   int rd;
   const char* fn = "prova.txt";
   int i = mkfifo(fn, 0666);
   int fd = open(fn, O_RDONLY); // | O_NONBLOCK);
   int flags = fcntl(fd, F_GETFL);
   //flags &= ~O_NONBLOCK;
   printf("1) Waits!\t\tflags=0%08o\n",flags);

   rd= read(fd, buf, 100);
   printf("%d %o\n",rd,flags);

   flags |= O_NONBLOCK;
   printf("2) Doesn't wait!\tflags=0%08o\n",flags);
   fcntl(fd, F_SETFL, flags);
   rd= read(fd, buf, 100);
   printf("%d %o\n",rd,flags);  

   //This doen't act the flag ????
   flags &= ~O_NONBLOCK;
   fcntl(fd, F_SETFL, flags);
   flags=fcntl(fd, F_GETFL);
   printf("3) Waits!\t\tflags=0%08o\n",flags);
   rd= read(fd, buf, 100);
   printf("%d %o\n",rd,flags);

   puts("End!");
   return 0;
}

这是命令序列和输出:

sergio@zarathustra:~$ ./a.out &
[2] 6555
sergio@zarathustra:~$ echo xxx >> prova.txt
1) Waits!       flags=000100000
4 100000
2) Doesn't wait!    flags=000104000
0 104000
3) Waits!       flags=000100000
0 100000
End!
sergio@zarathustra:~$ 

我查看了您的代码,乍一看它应该可以工作。没有错误 returned,你似乎没有违反任何规则,但它只是没有阻塞。

所以我继续跟踪 read 调用以查看它在做什么:

它一直到 the pipe_read function,没有任何阻挡。一旦到达那里,它就会意识到管道的另一边没有人,returns EOF。

所以这显然是设计使然,但是只有管道 open 调用会在没有编写器的情况下尝试阻塞,一旦 open returns 它只是假设有必须是该管道另一端的编写器,或者您是非阻塞的并准备好处理它。这有点道理。如果您尝试从管道 read 但写入器不在(或者一开始就不存在),您不想永远在那里等待。

如果您想等到编写器打开管道,请不要在 open 调用中使用 O_NONBLOCK。如果您确实在 open 中使用 O_NONBLOCK,那么管道的另一端可能没有任何人,并且 read 调用可能只是 return EOF 而不会阻塞。

所以简而言之,当你阅读它时,确保有人在管道的另一端。

您看到的行为是正常的。您已完成以下操作:

  1. 使用 O_NONBLOCK 打开 FIFO 的读取端,这样 FIFO 上就不需要写入程序了。这保证 open() 将立即成功。
  2. 在后续读取之前禁用 O_NONBLOCK。您现在已经回到了与标准(阻塞)情况相同的位置,其中 FIFO 具有 reader 和写入器,但写入器关闭了 FIFO。那时,reader 应该看到文件结尾,这就是您所看到的。