【问题标题】:How poll deal with closed pipepoll 如何处理封闭管道
【发布时间】:2013-08-20 10:33:21
【问题描述】:

我想知道:

pipe 关闭时,poll 将为管道的文件描述符设置什么状态?

我尝试下面的代码,在子进程关闭所有文件描述符后,轮询只是认为所有文件描述符都可以读取!那正确吗?还是只是我在这段代码中犯了一些错误?

我使用 SUSE 和 gcc。

#include <stdio.h>
#include <unistd.h>
#include "../../../myInclude/apue.h"// this is ok

#include <sys/poll.h>

int main(int argc, char **argv)
{
    int fd1[2]; int fd2[2]; int fd3[2];
    pid_t pid;
    if(pipe(fd1)<0 ||pipe(fd2)<0 ||pipe(fd3) <0)
        err_sys("pipe error");//this is a error deal function .it will exit the program and print error message.
    if((pid = fork()) <0)
        err_sys("fork() error");
    else if(pid == 0)
    {
        close(fd1[0]);
        close(fd2[0]);
        close(fd3[0]);

        if(write(fd1[1],"hello fd1 write!",17)!= 17)
            err_sys("write 1error ");
        sleep(2);
        if(write(fd2[1],"hello fd2 write!",17)!=17)
            err_sys("write 2error");
        sleep(2);
        if(write(fd3[1],"hello fd3 write!",17)!= 17)
            err_sys("write 3error");
        sleep(2);
        close(fd1[1]);
        close(fd2[1]);
        close(fd3[1]);
    }
    else
    {
        close(fd1[1]);
        close(fd2[1]);
        close(fd3[1]);
        struct pollfd fd[3];
        fd[0].fd = fd1[0];
        fd[1].fd = fd2[0];
        fd[2].fd = fd3[0];
        fd[0].events = POLLIN;
        fd[1].events = POLLIN;
        fd[2].events = POLLIN;
        while(poll(fd,3,3000) >0)
        {
            printf("now I come \n");
            int i = 0,n;
            char line[MAXLINE];
            for(; i< 3; i++)
            {
                if(fd[i].revents = POLLIN)
                        if ((n =read(fd[i].fd,line,MAXLINE))< 0)
                            err_sys("read error : %d",i);
                        else
                        {
                            line[n] = 0;
                            printf("read from pipe %d : %s\n",i,line);
                        }
            }
        }
        close(fd1[0]);
        close(fd2[0]);
        close(fd3[0]);
    }

    return 0;
}

我认为子进程关闭所有写入文件描述符后,轮询将设置revents POLLHUP。但它只是设置它POLLIN

我正在看这本书。我知道这是一本旧书。所以我想知道 poll 现在是如何工作的?是否为关闭管道设置了 POLLIN ?还是仅仅因为 Linux?还是我的代码错了?

【问题讨论】:

    标签: c linux pipe


    【解决方案1】:

    当管道的写入端关闭时,读取端对select()poll() 将显示为“可读” - 这是因为read() 不会阻塞。

    调用read()时,返回值为零,表示文件结束。

    【讨论】:

    • 书上说select 是可读的,而 poll 是 POLLHUP。你能解释更多或给我一个权威链接吗?
    • 您能否给我们参考这本书,以便我们知道为什么我们应该将它视为比poll() 的 POSIX 标准更权威?
    • @JonathanLeffler(和 caf):我可能错了,但我认为您误解了这个问题。他对poll 返回fd 并不感到惊讶;他很惊讶似乎没有设置POLLHUP。但是,由于编码错误,我们不知道这是否正确。
    • @rici:也许我理解错了……我主要是想了解他在用哪本书来了解它的内容。但是,鉴于您在回答中发现的错字,我认为我们可以将其修复,它可能会解决问题。
    【解决方案2】:

    您应该始终使用-Wall 选项编译您的程序(至少)。那会告诉你这个问题:

    if(fd[i].revents = POLLIN)
    

    条件将始终为真,因为这是一个赋值,而不是比较,并且POLLIN 不为零。以下内容也不正确,尽管更好:

    if(fd[i].revents == POLLIN)
    

    如果POLLINrevents 中设置的唯一标志,那将是正确的。也许这就是您认为要检查的内容,但正常的测试是:

    if(fd[i].revents & POLLIN)
    

    它将检查POLLIN 位是否已设置,表明read 不会阻塞。

    读取失败后可以检测到错误情况,因此实际上不需要检查是否设置了POLLHUP。在输入套接字上测试POLLHUP 不是一个好主意,因为即使数据可供读取,也可能会设置标志,并且通常需要读取数据。

    【讨论】:

    • +1 用于发现“明显的一次发现”错字。 (根据您的评论,我正在重新查看代码,看到了,然后看到您也看到了。)没有-Wall 的编译就像没有安全带的驾驶 - 危险但可行,但理智的人不会不要冒险。这也可以解释为什么 POLLIN 总是被设置。 (而且,如果可以的话,也可以为 if (fd[i].revents &amp; POLLIN) 修复另一个 +1)。
    猜你喜欢
    • 2014-05-09
    • 2011-07-19
    • 2012-08-08
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多