无法在Linux中使用fcntl切换到阻塞模式

6

我有一个样例程序:

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。请问您能解释一下这种行为吗?谢谢!


3
在这里,C++和C的区别重要吗? - hovnatan
cout << rd << endl; 是纯C++,但是所有的解释都在之前的链接中 https://dev59.com/yHE85IYBdhLWcg3wbS1h - Ôrel
2
是的,这可以很容易地用“printf”替换,并且与讨论无关。 - David C. Rankin
你是否在 flags &= ~O_NONBLOCK; 之前/之后检查过 flags,以确保按位取反实现了你需要的功能?为什么不在第二次调用 fcntl 时将 O_RDONLY 设置为 flags 进行测试呢? - David C. Rankin
作者应该先创建FIFO。 - Ôrel
显示剩余4条评论
3个回答

3
您看到的行为是正常的。您已经完成了以下操作:
  1. 使用O_NONBLOCK打开FIFO的读端,因此不需要在FIFO上存在写入者。这保证了open()将立即成功。
  2. 在后续读取之前禁用O_NONBLOCK。现在,您已经回到了一个等同于标准(阻塞)情况的位置,在该情况下FIFO有一个读取器和写入器,但写入器关闭了FIFO。此时,读取器应该看到文件结束符,这就是您看到的情况。

1

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

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

ftrace

而且它一直到the pipe_read function,没有任何尝试阻塞。一旦到达那里,它意识到管道的另一端没有人,并返回EOF。

所以这显然是设计上的,但是只有open调用会在没有写入者时尝试阻塞,一旦open返回,就假设该管道的另一端必须有一个写入者,或者您是非阻塞的并准备好处理。这也有点合理。如果您尝试从管道中read,但写入者已经消失(或者根本不存在),您不希望永远等待下去。

如果您想等待直到写入者打开管道,请不要在open调用中使用O_NONBLOCK。如果您在open中使用O_NONBLOCK,那么可能没有人在管道的另一端,read调用可能会立即返回EOF而不阻塞。

简而言之,在从管道中读取数据时,请确保管道的另一端有人。

0

很奇怪!我尝试了一段代码,它在不使用O_NONBLOCK的情况下打开文件,然后分为3个阶段进行。第三个阶段没有正确执行,尽管O_NONBLOCK标志已被重置!

#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:~$ 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接