【问题标题】:Why does poll keep returning although there is no input?为什么 poll 一直返回,尽管没有输入?
【发布时间】:2013-09-04 14:35:07
【问题描述】:

我编写了一个小测试程序来弄清楚如何与poll 交谈。我创建了三个文件 testa,testb,testc 并将字符串 hello\n 写入第一个文件。所以,这是我对poll 的调用:

poll(polls.data(),polls.size(),-1)

根据手册页,-1 的超时应该表明系统调用永远不会超时。但是,它不断返回而没有任何内容可供阅读。我总是消耗输入的一个字节并且可以看到正在打印的hello\n,但轮询并没有停止。它只是继续假装有东西可以读。

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

#include <vector>
#include <map>
#include <string>
#include <iostream>

typedef int fd_t;

int main() {
  fd_t const a = open("testa",O_RDONLY);
  fd_t const b = open("testb",O_WRONLY);
  fd_t const c = open("testc",O_RDWR);
  std::map<fd_t,std::string> names{{{a,"testa"},{b,"testb"},{c,"testc"}}};

  std::vector<pollfd> polls;
  polls.push_back(pollfd{a, POLLIN, 0});
  polls.push_back(pollfd{b, 0, 0});
  polls.push_back(pollfd{c, POLLIN, 0});

  while (poll(polls.data(),polls.size(),-1)) {
    for (auto p : polls) {
      if ((p.revents & (POLLIN|POLLERR)) == POLLIN) {
        std::cout << "{" << p.fd << ", " << p.events << ", " << p.revents << "} ";
        char byte;
        auto const rr = read(p.fd,&byte,1);
        auto const en = errno;
        if (rr) {
          std::cout << "File " << names[p.fd] << " says something: '" << ((int)byte) << " (" << (((' '<byte) && (byte<127))?byte:'\0') << ")" << "' \n";
        } else {
          std::cout << "Strange (file " << names[p.fd] << "). errno says " << en << "\n";
        }
      }
    }
  }
}

我得到的是这样的:

{3, 1, 1} File testa says something: '104 (h)' 
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} File testa says something: '101 (e)' 
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} File testa says something: '108 (l)' 
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} File testa says something: '108 (l)' 
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} File testa says something: '111 (o)' 
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} File testa says something: '10 ()' 
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} Strange (file testa). errno says 0
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} Strange (file testa). errno says 0
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} Strange (file testa). errno says 0
{5, 1, 1} Strange (file testc). errno says 0
{3, 1, 1} Strange (file testa). errno says 0
{5, 1, 1} Strange (file testc). errno says 0

(永远重复最后两行)

我在 3.10-2-amd64 内核上使用 g++ -Wall -Wextra -std=c++11 poll.cpp -o poll 构建。

【问题讨论】:

  • 你如何知道 EOF 何时出现?

标签: c++ linux file-descriptor poll-syscall


【解决方案1】:

常规文件中的 EOF 条件仍然可读。换句话说,您的read() 不会被阻止。以下是poll() 的不同实现如何在不同类型的文件描述符中对 EOF 做出反应的一个很好的列表:http://www.greenend.org.uk/rjk/tech/poll.html

请注意,常规文件总是返回 POLLIN。所以你需要单独测试EOF。事实上,对常规文件进行轮询对您没有任何作用。您将需要套接字或管道或其他东西来测试您的代码。

其他注意事项:您可能想检查.revents 中的其他结果。 POLLERR、POLLHUP 和 POLLNVAL 都表示不同的错误情况,需要特殊处理。

【讨论】:

  • 感谢您的解释。我希望 EOF 像文件被阻止一样被处理。我现在正在尝试使用命名管道(实际上只有一个(testa)),但现在poll 根本不返回,而echo a &gt; testa 则返回(当我的程序运行时)。有什么想法吗?
  • 是的,这就是重点。来自命名管道的read() 将阻塞,直到数据可用。 poll() 在您的命名管道可读之前根本不应该返回,当您将字符回显到其中时会发生这种情况。
  • 是的,但这不会发生。即使我将数据写入管道,poll 不会返回。 echo a &gt;&gt; testa 命令返回(所以我假设数据已写入管道)但在我的程序中,poll 没有返回。
  • 非常适合我...我只是使用了你的代码,注释掉了 testb 和 testc,mkfifo testa,运行程序,然后 echo a &gt;&gt; testa。如果您的代码被修改,请发布。同时显示ls -l test*
【解决方案2】:

一旦到达文件末尾,它仍然可读,因此poll 将立即返回,而调用read 将立即返回零。您需要处理这种情况,可能通过关闭它并将其从当前正在打印Strange 的轮询集中删除。

【讨论】:

    【解决方案3】:

    本地文件描述符总是准备好执行 I/O(与套接字不同,因为它们依赖于内核内部缓冲区进行 I/O)。在您的情况下,文件描述符始终可以读取,即使它们实际上是空的。

    【讨论】:

      猜你喜欢
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多