【问题标题】:using select() with pipe将 select() 与管道一起使用
【发布时间】:2026-02-08 09:50:01
【问题描述】:

我正在读/写pipe(pipe_fds) 创建的管道。所以基本上使用以下代码,我正在从该管道读取:

fp = fdopen(pipe_fds[0], "r"); 

每当我得到一些东西时,我都会通过以下方式打印出来:

while (fgets(buf, 200, fp)) {
    printf("%s", buf);
}

我想要的是,当一段时间内piperead 上没有出现任何内容时,我想知道并做:

printf("dummy");

这可以通过select() 实现吗?任何关于如何做到这一点的指示都会很棒。

【问题讨论】:

    标签: c unix pipe


    【解决方案1】:

    假设您想等待 5 秒,然后如果没有任何内容写入管道,则打印出“dummy”。

    fd_set set;
    struct timeval timeout;
    
    /* Initialize the file descriptor set. */
    FD_ZERO(&set);
    FD_SET(pipe_fds[0], &set);
    
    /* Initialize the timeout data structure. */
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    
    /* In the interest of brevity, I'm using the constant FD_SETSIZE, but a more
       efficient implementation would use the highest fd + 1 instead. In your case
       since you only have a single fd, you can replace FD_SETSIZE with
       pipe_fds[0] + 1 thereby limiting the number of fds the system has to
       iterate over. */
    int ret = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
    
    // a return value of 0 means that the time expired
    // without any acitivity on the file descriptor
    if (ret == 0)
    {
        printf("dummy");
    }
    else if (ret < 0)
    {
        // error occurred
    }
    else
    {
        // there was activity on the file descripor
    }
    

    【讨论】:

    • 很确定ret == 0 也被中断了。
    • 中断将导致select() 返回-1,errno 设置为EINTR
    • 一个改进您的答案的建议:OP 在这里使用 read(2) 而不是 fgets(3) 可能是谨慎的。
    • @unluddite:非常感谢代码 sn-p。所以,在最后一个else,我应该做我的常规打印(我的while(fgets ....循环),因为当ret &gt; 0时,这表明我有一些文件要阅读。
    • 因为fd_set 是一个固定大小的数组(大小为FD_SETSIZE)。它有一个文件描述符可以拥有的所有可能值的插槽(在大多数系统上最多为 1024)。当您调用FD_SET 时,它使用文件描述符编号来索引数组。来自文档:“select()函数测试0nfds-1范围内的文件描述符”所以我们需要加1以确保我们的文件描述符在范围内。
    【解决方案2】:

    IIRC,select 有一个超时,然后您检查 FD_ISSET 以判断它是否返回了 I/O。

    【讨论】: