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

时间:2015-04-12 07:59:39

标签: c linux io nonblocking fcntl

我有一个示例程序:

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 个答案:

答案 0 :(得分:2)

您所看到的行为是预期的。您已完成以下操作:

  1. 使用O_NONBLOCK打开FIFO的读取端,因此FIFO上不需要存在写入器。这可以保证open()立即成功。
  2. 在后续读取之前禁用O_NONBLOCK。您现在已经回到了一个与标准(阻塞)情况相同的位置,其中FIFO具有读写器,但编写器关闭了FIFO。此时,读者应该看到文件结束,这就是你所看到的。

答案 1 :(得分: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:~$ 

答案 2 :(得分:0)

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

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

ftrace

它一直到the pipe_read function而没有任何阻止的尝试。一旦它在那里它意识到管道的另一侧没有人并返回EOF。

所以这显然是设计的,但只有管道只有open调用会尝试阻止,如果没有编写器,一旦open返回它,只是假设在另一个必须有一个编写器该管道的末端或您没有阻塞并准备好处理它。这有点道理。如果你试图从管道read但是作者已经离开(或者从来没有在那里),你不想永远在那里等待。

如果您想等到作家打开管道,请不要在O_NONBLOCK电话中使用open。如果您在O_NONBLOCK中使用open,那么管道的另一端可能没有任何人,而read调用可能只是在不阻止的情况下返回EOF。

所以简而言之,当你从中读取时,确保管道的另一端有人。