#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>
// cc.byexamples.com calls this int kbhit(), to mirror the Windows console
// function of the same name. Otherwise, the code is the same.
bool inputAvailable()
{
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return (FD_ISSET(0, &fds));
}
int main(int argc, char* argv[])
{
std::string initialCommand;
if (argc > 1) {
// Code to get the initial command from a file
} else {
while (!inputAvailable()) {
std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl;
sleep(1);
}
std::getline(std::cin, initialCommand);
}
// Start a thread class instance 'jobThread' to run the command
// Start a thread class instance 'inputThread' to look for further commands
return 0;
}
8条答案
按热度按时间pbgvytdp1#
我想补充一个例子:
运行此程序时,您有4秒钟时间向标准输入提供输入。如果没有找到输入,它将返回。
2个样本执行:
7jmck4yq2#
就像Pete Kirkham一样,我找到了cc.byexamples.com,它对我很有效。去那里获得对问题的很好的解释,以及ncurses版本。
我的代码需要从标准输入或文件中获取初始命令,然后在处理初始命令时监视cancel命令。我的代码是C++,但你应该能够使用
scanf()
,其余的我使用C++输入函数getline()
。meat是一个函数,用于检查是否有任何可用的输入:
这必须在任何stdin输入函数之前调用当我在使用这个函数之前使用
std::cin
时,它再也没有返回true。例如,main()
有一个循环,看起来像这样:在输入线程中,新命令被添加到队列中,该队列由
jobThread
周期性地处理。inputThread
看起来有点像这样:这个函数可能已经存在于
main()
中,但我使用的是现有的代码库,而不是针对它。对于我的系统来说,在发送一个换行符之前没有可用的输入,这正是我所想要的。如果你想在输入时读取每个字符,你需要关闭标准输入中的“规范模式”。cc.byexamples.com有一些我没有尝试过的建议,但其余的工作,所以它应该工作。
50few1ms3#
你真的不知道TTY(控制台)是一个非常有限的设备,你几乎不做非阻塞I/O。当你看到一些看起来像非阻塞I/O的东西时,比如在curses/ncurses应用程序中,你所做的就是所谓的 raw I/O。在原始I/O中,没有字符的解释,没有擦除处理等。相反,您需要编写自己的代码,在执行其他操作时检查数据。
在现代C程序中,您可以通过将控制台I/O放入一个 * 线程 * 或轻量级进程中来简化这一点。然后,I/O可以以通常的阻塞方式继续,但数据可以插入到队列中,以便在另一个线程上处理。
更新
这里有一个curses tutorial,它涵盖了更多。
uklbhaso4#
本月早些时候,当我认为我可能需要非阻塞、非缓冲的控制台输入时,我将“Non-blocking user input in loop without ncurses”作为书签,但我没有,所以不能保证它是否有效。对于我的使用,我不在乎它直到用户按回车键才得到输入,所以只使用aio来读取stdin。
3bygqnnd5#
下面是一个使用C++的相关问题--Cross-platform (linux/Win32) nonblocking C++ IO on stdin/stdout/stderr
wlzqhblo6#
使用ncurses或线程的另一种替代方法是使用GNU Readline,特别是它允许您register callback functions的部分。模式则为:
1.在STDIN上使用select()(以及其他描述符)
1.当select()告诉您可以读取STDIN时,调用readline的rl_callback_read_char()
1.如果用户输入了完整的行,rl_callback_read_char将调用您的回调。否则,它将立即返回,您的其他代码可以继续。
pn9klfpd7#
让我们看看它是如何在Linux工具之一。例如,perf/builtin-top.c源(简化):
所以,如果你想检查是否有可用的数据,你可以像这样使用poll()或select():
在这种情况下,按下[RETURN]键后,您将不会在每个键上接收事件,而是在整行上接收事件。这是因为terminal在canonical mode中运行(输入流被缓冲,当按下[RETURN]时缓冲区刷新):
在规范输入处理模式下,终端输入在以换行符('\n')、EOF或EOL字符终止的行中处理。在用户输入整行之前,不能读取任何输入,并且read函数(请参阅输入和输出原语)最多返回一行输入,无论请求多少字节。
如果你想立即读取字符,你可以使用noncanonical mode。使用tcsetattr()切换:
简单程序(link to playground):
7gs2gvoe8#
不完全确定您所说的“控制台IO”是什么意思--您是从STDIN阅读,还是这是一个从其他源读取的控制台应用程序?
如果从STDIN阅读,则需要跳过fread(),使用read()和write(),并使用poll()或select()来防止调用阻塞。您可以使用setbuf()禁用输入缓冲,这应该会导致fread返回EOF,但我从未尝试过。