C - select() on stdin when there is already data in stdin's buffer

时光总嘲笑我的痴心妄想 提交于 2019-12-13 02:44:10

问题


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)

So I expected, that select in the following program would immediately return in the 2nd, ... iteration, if you enter a string > 4 characters in the first iteration. However it does not. Just after pressing any other key after the first output it continues to handle all the remaining input. Why?

Sample output:

./selectTest
12345678900
Keyboard input received: 1234
A
Keyboard input received: 5678
Keyboard input received: 900

Keyboard input received: A

Code

#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;
}

(I know, that I should not use select() anymore, but I am learning for an exam and we have to ...)


回答1:


You are reading from a tty(4) (in the usual case when stdin is your terminal). These are tricky things, read the tty demystified.

Be aware that your terminal and its tty has some line discipline. So, some data is buffered in the kernel (and also in the standard library).

You might want to put your tty in raw mode. See termios(3) & stty(1)

But don't lose your time, instead use some library like ncurses or readline

To play with select, you might use some fifo(7), perhaps with mkfifo /tmp/myfifo then yourprogram < /tmp/myfifo and, in another terminal, echo hello > /tmp/myfifo




回答2:


Fundamentally, the problem is that you're mixing buffered stdio streams with low-level I/O. The reason the select is blocking is because the previously typed data has already been read and is buffered in stdin's stream data buffer. Try setting stdin to unbuffered mode by calling setbuf(stdin, NULL).



来源:https://stackoverflow.com/questions/34067884/c-select-on-stdin-when-there-is-already-data-in-stdins-buffer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!