【问题标题】:cannot switch to blocking mode using fcntl in linux无法在 linux 中使用 fcntl 切换到阻塞模式
【发布时间】:2015-06-17 16:47:43
【问题描述】:

我有一个示例程序:

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 结果。你能解释一下这种行为吗?谢谢!

【问题讨论】:

  • 看起来像 C++ 而不是 C。见 stackoverflow.com/questions/2784500/…
  • c++、c 的区别在这里重要吗?
  • 当您从 fifo 读取结果为 rd = 0 时,errno 的值是否有任何变化?
  • cout &lt;&lt; rd &lt;&lt; endl; 是纯 C++,但一切都在上一个链接 stackoverflow.com/questions/2784500/… 中进行了解释
  • 是的,可以很容易地用printf 替换,并且与讨论无关。

标签: c linux io nonblocking fcntl


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    这很奇怪!我尝试了一个代码,它在没有 O_NONBLOCK 的情况下打开文件,然后分三个阶段进行。尽管 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:~$ 
    

    【讨论】:

      【解决方案3】:

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

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

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

      所以这显然是设计使然,但是对于管道,如果没有写入器,则只有 open 调用会尝试阻塞,一旦 open 返回它只是假设该管道的另一端必须有写入器或者你没有阻塞并准备好处理它。这有点道理。如果您尝试通过管道发送read,但作者已不在(或者从一开始就不存在),您不想永远等待在那里。

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

      因此,简而言之,当您阅读管道时,请确保有人在管道的另一端。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-11
        • 1970-01-01
        • 1970-01-01
        • 2014-11-22
        • 1970-01-01
        • 2011-12-18
        • 1970-01-01
        • 2011-07-14
        相关资源
        最近更新 更多