为什么第二个或循环的 select() 会阻塞?

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

我在使用管道

时被
select()堵塞。当我们在标准输入上获取数据时,第一个
select()
将解锁(我只需输入一个字母并按 Enter)。

然后我将数据写入管道的写入端,但是

select()
无法识别管道读取fd上的任何数据。所以它会无限期地阻塞。

int    fd_pipe[2];
char   buf[20];
fd_set set;

pipe(fd_pipe);

FD_ZERO(&set);
FD_SET(fd_pipe[0], &set); // Pipe read fd
FD_SET(0         , &set); // stdin fd

select(fd_pipe[0]+1, &set, NULL, NULL, NULL); // I type 1 char + ENTER to get past this point

if (FD_ISSET(0, &set))
{
    read(0, buf, 20);          // Can confirm we do get here
    write(fd_pipe[1], buf, 1); // Lets put just one character in the pipe
}

select(fd_pipe[0]+1, &set, NULL, NULL, NULL); // <-- We get stuck here

if (FD_ISSET(fd_pipe[0], &set))
{
    char d;
    read(0, &d, 1);
    assert(d == buf[0]);
}

如果我在没有

select()
的情况下执行此操作,则一切正常:

int fd_pipe[2];
pipe(fd_pipe);

char c = 'x';
write( fd_pipe[1], &c, 1);

c = 'a';
read( fd_pipe[0], &c, 1);

assert(c == 'x');

在更大的图中,我有一个多线程程序,它使用

select()
pipe()
来模拟取消
read()
操作。我用单个字符写入管道,目的是强制
select()
返回,以便我可以关闭操作,而不是尝试发送信号来取消主 FD 上的阻塞
read()
。但
select()
没有回来。

c pipe posix posix-select
1个回答
7
投票

select
函数会修改您传递给它的集合。当
select
返回时,集合将仅包含活动描述符。

在您的情况下,只会设置

STDIN_FILENO
,因此第二次调用
select
时不会有
fd_pipe[0]

解决方案实际上不是将管道重新添加到集合中并再次调用

select
,而是只调用
select
一次:

FD_ZERO(&set);
FD_SET(fd_pipe[0], &set); // Pipe read fd
FD_SET(0         , &set); // stdin fd

select(fd_pipe[0]+1, &set, NULL, NULL, NULL); // I type 1 char + ENTER to get past this point

if (FD_ISSET(0, &set))
{
    read(0, buf, 20);          // Can confirm we do get here
    write(fd_pipe[1], buf, 1); // Lets put just one character in the pipe
}
else if (FD_ISSET(fd_pipe[0], &set))
{
    char d;
    read(fd_pipe[0], &d, 1);
    assert(d == buf[0]);
}

您还需要检查

select
实际返回什么。它可能会返回
-1
,这意味着存在错误。


如果您确实需要多次致电

select
。然后您需要重新调零/重新设置
fd_set

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