【问题标题】:C - select() on stdin when there is already data in stdin's bufferC - 当标准输入的缓冲区中已有数据时,标准输入上的 select()
【发布时间】:2015-12-03 13:56:21
【问题描述】:

select 函数会阻塞调用进程,直到任何指定的文件描述符集有活动[...] 如果读取调用不会阻塞,则认为文件描述符已准备好读取。 (见:https://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html

所以我预计,如果您在第一次迭代中输入 > 4 个字符的字符串,则以下程序中的 select 将在第二次迭代中立即返回 ...然而事实并非如此。在第一次输出后按下任何其他键后,它会继续处理所有剩余的输入。为什么?

示例输出:

./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(),但我正在为考试而学习,我们必须...)

【问题讨论】:

  • 你有什么问题?

标签: c linux select posix


【解决方案1】:

从根本上说,问题在于您将缓冲的 stdio 流与低级 I/O 混合在一起。 select 阻塞的原因是先前键入的数据已经被读取并缓冲在stdin 的流数据缓冲区中。尝试通过调用setbuf(stdin, NULL)stdin 设置为无缓冲模式。

【讨论】:

  • 这是真的,但可能不是问题的唯一原因。
  • while 循环之前添加对setbuf(stdin, NULL); 的调用似乎可以解决它。好吧,除了缺少文件结束检测之外,“修复它”,但这是一个单独的问题!
【解决方案2】:

您正在阅读tty(4)(通常情况下,stdin 是您的终端)。这些都是棘手的事情,请阅读tty demystified

请注意,您的终端及其 tty 有一些 line discipline。因此,一些数据被缓冲在内核中(也包括在标准库中)。

您可能希望将您的 tty 置于原始模式。见termios(3) & stty(1)

但不要浪费时间,而是使用一些库,如 ncursesreadline

要使用select,您可以使用一些fifo(7),可能使用mkfifo /tmp/myfifo,然后使用yourprogram &lt; /tmp/myfifo,在另一个终端中使用echo hello &gt; /tmp/myfifo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多