如何在C语言的Linux/OS X上进行非阻塞控制台IO?
像Pete Kirkham一样,我找到了cc.byexamples.com,它对我有用.去那里找一个问题的好解释,以及ncurses版本.
我的代码需要从标准输入或文件中获取初始命令,然后在处理初始命令时监视取消命令.我的代码是C++,但你应该能够使用scanf(),其余的我使用C++输入函数getline().
肉是一个检查是否有任何可用输入的函数:
#include#include #include // 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)); }
必须在任何stdin输入函数之前调用它.当我在使用这个函数之前使用std :: cin时,它再也没有返回true.例如,main()有一个如下所示的循环:
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; }
在输入线程中,新命令被添加到队列中,该队列由jobThread定期处理.inputThread看起来有点像这样:
THREAD_RETURN inputThread() { while( !cancelled() ) { if (inputAvailable()) { std::string nextCommand; getline(std::cin, nextCommand); commandQueue.lock(); commandQueue.add(nextCommand); commandQueue.unlock(); } else { sleep(1); } } return 0; }
这个函数可能在main()中,但我正在使用现有的代码库,而不是它.
对于我的系统,在发送换行符之前没有可用的输入,这正是我想要的.如果要在键入时读取每个字符,则需要在stdin上关闭"规范模式". cc.byexamples.com有一些我没有尝试过的建议,但其余的都有用,所以应该可行.
我想添加一个例子:
#include#include #include int main(int argc, char const *argv[]) { char buf[20]; fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK); sleep(4); int numRead = read(0,buf,4); if(numRead > 0){ printf("You said: %s", buf); } }
当你运行这个程序时,你有4秒的时间为标准输入提供输入.如果没有找到输入,它将不会阻塞,只会返回.
2个样本执行:
Korays-MacBook-Pro:~ koraytugay$ ./a.out fda You said: fda Korays-MacBook-Pro:~ koraytugay$ ./a.out Korays-MacBook-Pro:~ koraytugay$
你没有,真的.TTY(控制台)是一个非常有限的设备,你几乎不做非阻塞I/O. 当你看到的东西,看起来像非阻塞I/O,说在诅咒/ ncurses的应用程序,是叫你做什么原始I/O.在原始I/O中,没有对字符的解释,没有擦除处理等.相反,您需要编写自己的代码来检查数据,同时执行其他操作.
在现代C程序中,您可以通过将控制台I/O放入线程或轻量级进程来简化这种方式.然后I/O可以以通常的阻塞方式继续,但是数据可以插入到队列中以在另一个线程上处理.
这是一个curses教程,它涵盖了更多内容.
本月早些时候,当我认为我可能需要非阻塞,非缓冲的控制台输入时,我将" 非阻塞用户输入循环而没有ncurses " 加入书签,但我没有,因此无法保证它是否有效.对于我的使用,我并不关心它在用户点击输入之前没有输入,所以只是使用aio来读取标准输入.