C - select() 当标准输入的缓冲区中已经有数据时在标准输入上
C - select() on stdin when there is already data in stdin's buffer
The select function blocks the calling process until there is activity on any of the specified sets of file descriptors [...] A file descriptor is considered ready for reading if a read call will not block. (See: https://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html)
所以我预计,如果您在第一次迭代中输入大于 4 个字符的字符串,则以下程序中的 select 会在第二次...迭代中立即 return。然而事实并非如此。在第一次输出后按下任何其他键后,它会继续处理所有剩余的输入。为什么?
示例输出:
./selectTest
12345678900
Keyboard input received: 1234
A
Keyboard input received: 5678
Keyboard input received: 900
Keyboard input received: A
代码
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(void)
{
fd_set rfds;
char buf[100];
while(1)
{
FD_ZERO(&rfds);
FD_SET(fileno(stdin), &rfds);
if(-1 == select(FD_SETSIZE, &rfds, NULL, NULL, NULL))
{
perror("select() failed\n");
}
if(FD_ISSET(fileno(stdin), &rfds))
{
printf("Keyboard input received: ");
fgets(buf, 5, stdin);
printf("%s\n", buf);
}
}
return 0;
}
(我知道,我不应该再使用 select(),但我正在为考试而学习,我们必须...)
您正在阅读 tty(4) (in the usual case when stdin is your terminal). These are tricky things, read the tty demystified。
请注意您的终端及其 tty 有一些 line discipline。因此,一些数据被缓冲在内核中(以及标准库中)。
您可能希望将您的 tty 置于原始模式。参见 termios(3) & stty(1)
但是不要浪费时间,而是使用像 ncurses or readline
这样的库
要使用 select
,您可以使用一些 fifo(7),也许使用 mkfifo /tmp/myfifo
,然后使用 yourprogram < /tmp/myfifo
,然后在另一个终端中使用 echo hello > /tmp/myfifo
从根本上说,问题在于您将缓冲的 stdio 流与低级 I/O 混合在一起。 select
阻塞的原因是因为先前键入的数据已被读取并缓冲在 stdin
的流数据缓冲区中。尝试通过调用 setbuf(stdin, NULL)
.
将 stdin
设置为无缓冲模式
The select function blocks the calling process until there is activity on any of the specified sets of file descriptors [...] A file descriptor is considered ready for reading if a read call will not block. (See: https://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html)
所以我预计,如果您在第一次迭代中输入大于 4 个字符的字符串,则以下程序中的 select 会在第二次...迭代中立即 return。然而事实并非如此。在第一次输出后按下任何其他键后,它会继续处理所有剩余的输入。为什么?
示例输出:
./selectTest
12345678900
Keyboard input received: 1234
A
Keyboard input received: 5678
Keyboard input received: 900
Keyboard input received: A
代码
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(void)
{
fd_set rfds;
char buf[100];
while(1)
{
FD_ZERO(&rfds);
FD_SET(fileno(stdin), &rfds);
if(-1 == select(FD_SETSIZE, &rfds, NULL, NULL, NULL))
{
perror("select() failed\n");
}
if(FD_ISSET(fileno(stdin), &rfds))
{
printf("Keyboard input received: ");
fgets(buf, 5, stdin);
printf("%s\n", buf);
}
}
return 0;
}
(我知道,我不应该再使用 select(),但我正在为考试而学习,我们必须...)
您正在阅读 tty(4) (in the usual case when stdin is your terminal). These are tricky things, read the tty demystified。
请注意您的终端及其 tty 有一些 line discipline。因此,一些数据被缓冲在内核中(以及标准库中)。
您可能希望将您的 tty 置于原始模式。参见 termios(3) & stty(1)
但是不要浪费时间,而是使用像 ncurses or readline
这样的库要使用 select
,您可以使用一些 fifo(7),也许使用 mkfifo /tmp/myfifo
,然后使用 yourprogram < /tmp/myfifo
,然后在另一个终端中使用 echo hello > /tmp/myfifo
从根本上说,问题在于您将缓冲的 stdio 流与低级 I/O 混合在一起。 select
阻塞的原因是因为先前键入的数据已被读取并缓冲在 stdin
的流数据缓冲区中。尝试通过调用 setbuf(stdin, NULL)
.
stdin
设置为无缓冲模式