为什么poll()立即在常规文件上返回并在fifo上阻止?

问题描述 投票:0回答:1

我多次检查此代码,不明白为什么poll()立即返回?

这里文件已打开以供读取,应等待事件。如何使其等待输入?

#include <iostream>

#include <poll.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>


using namespace std;

ssize_t read_out_to_the_end(int fd){
   char chunk[1024];
   ssize_t ret = 0, n;
   while((n = ::read(fd, chunk, sizeof chunk)) > 0){
      ret += n;
      cerr << "read chunk: " << n << " | ";
      cerr.write(chunk, n);
      cerr << endl;
   }
   if (n < 0) {
       cerr << "err in read" << endl;
   }
   else if (ret == 0){
      cerr << "nothing to read" << endl;
   }
   return ret;
}

int main() {
   int bininfd = open("bin-in", O_RDONLY | O_CREAT);//, 0644/*S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH*/);
   if (bininfd < 0) {
      perror("err in open(binin)");
      return -1;
   }

   struct pollfd pollfds[] = {
         {bininfd, POLLIN, 0},
   };
   auto&[pfd] = pollfds;

   while (1) {
      pfd.revents = 0;  // cleanup, shouldn't it be redundant
      int pollret = poll(pollfds, 1, -1);
      if (pollret > 0) {
         if (pfd.revents & POLLIN) {
            cerr << "(pfd.revents & POLLIN)" << endl;
            read_out_to_the_end(pfd.fd);
         }
      } else if (pollret == 0) {
         cerr << "poll timed out" << endl;
         continue;
      } else {
         cerr << "check for error" << endl;
         continue;
      }
   }
}

输出为

(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
............... etc ....................

live example

更新:1. read_out_to_the_end()已修复。感谢@RemyLebeau2.它适用于fifos,但不适用于常规文件

c++ posix polling file-descriptor
1个回答
0
投票

read_out_to_the_end()有几个问题:

  • ret未初始化。

  • while循环在应分配n时递增。但是,如果while循环达到EOF,则即使在达到EOF之前实际读取了数据,if( n == 0)也将为true。

  • chunk可以为空值终止,但是根据输入数据,它也可能也接收空值。因此,不应使用cerr将其写入cout(为什么不使用operator<<?),请改用cerr.write(),以便您可以将读取的实际字节数传递给它。

尝试以下方法:

ssize_t read_out_to_the_end(int fd){
   char chunk[1024];
   ssize_t ret = 0, n;
   while((n = ::read(fd, chunk, sizeof chunk)) > 0){
      ret += n;
      cerr << "read chunk: " << n << " | ";
      cerr.write(chunk, n);
      cerr << endl;
   }
   if (n < 0) {
       cerr << "err in read" << endl;
   }
   else if (ret == 0){
      cerr << "nothing to read" << endl;
   }
   return ret;
}

int main() {
   int bininfd = open("bin-in", O_RDONLY | O_CREAT);//, 0644/*S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH*/);
   if (bininfd < 0) {
      perror("err in open(binin)");
      return -1;
   }

   pollfd pfd = {};
   pfd.fd = bininfd;
   pfd.events = POLLIN;

   while (true) {
      pfd.revents = 0;  // cleanup, shouldn't it be redundant
      int pollret = poll(&pfd, 1, -1);
      if (pollret > 0) {
         if (pfd.revents & POLLIN) {
            cerr << "(pfd.revents & POLLIN)" << endl;
            read_out_to_the_end(pfd.fd);
         }
      } else if (pollret == 0) {
         cerr << "poll timed out" << endl;
         continue;
      } else {
         cerr << "poll error " << errno << endl;
         break;
      }
   }
}

此外,open() documentation说:

open()自变量指定在创建新文件时应用的文件模式位。 [mode中指定O_CREAT或O_TMPFILE时必须提供此参数];如果既未指定O_CREAT也未指定O_TMPFILE,则忽略flags。有效模式由进程的mode以通常的方式修改:在没有默认ACL的情况下,创建的文件的模式为umask。请注意,此模式仅适用于将来对新创建文件的访问。创建只读文件的(mode & ~umask)调用很可能会返回读/写文件描述符。

© www.soinside.com 2019 - 2024. All rights reserved.