使用select()函数和管道

8

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

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

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

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

我希望的是,当一定时间内没有数据从管道中可读取时,我想知道并执行以下操作:

printf("dummy");

这可以通过 select() 函数实现吗?如何实现请指点。

2个回答

12

假设你想等待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
}

2
很确定在中断时 ret == 0 - Aaron D. Marasco
5
中断会导致select()返回-1,同时将errno设置为EINTR - Eugene S
3
改进您的回答建议:为了更谨慎,建议原帖使用read(2)而非fgets(3)函数。 - Joseph Quinsey
@unluddite:非常感谢您详细的回答。我有一个最后的问题:当我们说第一个参数是 pipe_fds[0] + 1 时,这是什么意思?我只想让 select 观察 pipe_fds[0],而不观察其他任何东西,那么为什么要加上 +1?这有什么作用? - hari
1
因为fd_set是一个固定大小的数组(大小为FD_SETSIZE)。它有一个插槽,用于存储文件描述符可能具有的所有可能值(在大多数系统上最多可达1024个)。当您调用FD_SET时,它使用文件描述符号码索引到数组中。从文档中可以看出:“select()函数测试范围内的文件描述符为“0”到“nfds-1”,因此我们需要添加1以确保我们的文件描述符在范围内。 - Eugene S
显示剩余6条评论

0
据我所知,select有一个超时时间,然后你可以使用FD_ISSET来检查它是否是I/O返回的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接