非阻塞控制台输入 C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6171132/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Non-blocking console input C++
提问by Doug
I'm looking for a (multiplatform) way to do non-blocking console input for my C++ program, so I can handle user commands while the program continually runs. The program will also be outputting information at the same time.
我正在寻找一种(多平台)方式来为我的 C++ 程序进行非阻塞控制台输入,这样我就可以在程序持续运行的同时处理用户命令。程序也会同时输出信息。
What's the best/easiest way to do this? I have no problem using external libraries like boost, as long as they use a permissive license.
最好/最简单的方法是什么?我使用像 boost 这样的外部库没有问题,只要它们使用宽松的许可证。
采纳答案by Seth Carnegie
I would do this by creating separate a thread which calls normal blocking IO functions and pass it a callback function which it would call when it got input. Are you sure you need to do what you said you want to do?
我将通过创建一个单独的线程来实现这一点,该线程调用正常的阻塞 IO 函数并将其传递给一个回调函数,当它获得输入时将调用该函数。你确定你需要做你说你想做的事吗?
As for outputting information at the same time, what would happen if the user was in the middle of typing some input and you printed something?
至于同时输出信息,如果用户正在输入一些输入并且你打印一些东西会发生什么?
回答by Sascha
Example using C++11:
使用 C++11 的示例:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
static std::string getAnswer()
{
std::string answer;
std::cin >> answer;
return answer;
}
int main()
{
std::chrono::seconds timeout(5);
std::cout << "Do you even lift?" << std::endl << std::flush;
std::string answer = "maybe"; //default to maybe
std::future<std::string> future = std::async(getAnswer);
if (future.wait_for(timeout) == std::future_status::ready)
answer = future.get();
std::cout << "the answer was: " << answer << std::endl;
exit(0);
}
online compiler: https://rextester.com/GLAZ31262
在线编译器:https: //rextester.com/GLAZ31262
回答by Rihard S
There is one easy way:
有一种简单的方法:
char buffer[512];
int point = 0;
...
while (_kbhit()) {
char cur = _getch();
if (point > 511) point = 511;
std::cout << cur;
if (cur != 13) buffer[point++] = cur;
else{
buffer[point] = 'while (!g_quit)
{
//we want to receive data from stdin so add these file
//descriptors to the file descriptor set. These also have to be reset
//within the loop since select modifies the sets.
FD_ZERO(&read_fds);
FD_SET(STDIN_FILENO, &read_fds);
result = select(sfd + 1, &read_fds, NULL, NULL, NULL);
if (result == -1 && errno != EINTR)
{
cerr << "Error in select: " << strerror(errno) << "\n";
break;
}
else if (result == -1 && errno == EINTR)
{
//we've received and interrupt - handle this
....
}
else
{
if (FD_ISSET(STDIN_FILENO, &read_fds))
{
process_cmd(sfd);
}
}
}
';
point = 0;
//Run(buffer);
}
}
No block, all in 1 thread. As for me, this works.
没有阻塞,全部在 1 个线程中。至于我,这有效。
回答by sashang
I've done this on QNX4.5 that doesn't support threads or Boost by using select
. You basically pass select
STDIN as the file descriptor to use and select will return when a new line is entered. I've added a simplified example loop below. It's platform independent, at least for Unix like systems. Not sure about Windows though.
我已经在不支持线程或 Boost 的 QNX4.5 上使用select
. 您基本上将select
STDIN 作为要使用的文件描述符传递,并且 select 将在输入新行时返回。我在下面添加了一个简化的示例循环。它是独立于平台的,至少对于类 Unix 系统而言是这样。虽然不确定Windows。
#include <iostream>
#include <memory>
#include <string>
#include <future>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
int main()
{
std::mutex m;
std::condition_variable cv;
std::string new_string;
bool error = false;
auto io_thread = std::thread([&]{
std::string s;
while(!error && std::getline(std::cin, s, '\n'))
{
auto lock = std::unique_lock<std::mutex>(m);
new_string = std::move(s);
if (new_string == "quit") {
error = true;
}
lock.unlock();
cv.notify_all();
}
auto lock = std::unique_lock<std::mutex>(m);
error = true;
lock.unlock();
cv.notify_all();
});
auto current_string = std::string();
for ( ;; )
{
auto lock = std::unique_lock<std::mutex>(m);
cv.wait(lock, [&] { return error || (current_string != new_string); });
if (error)
{
break;
}
current_string = new_string;
lock.unlock();
// now use the string that arrived from our non-blocking stream
std::cout << "new string: " << current_string;
std::cout.flush();
for (int i = 0 ; i < 10 ; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << " " << i;
std::cout.flush();
}
std::cout << ". done. next?\n";
std::cout.flush();
}
io_thread.join();
return 0;
}
回答by Richard Hodges
Non-blocking console input C++ ?
非阻塞控制台输入 C++ ?
Ans: do console IO on a background thread and provide a means of communicating between threads.
Ans:在后台线程上执行控制台 IO 并提供线程之间的通信方式。
Here's a complete (but simplistic) test program that implements async io by deferring the io to a background thread.
这是一个完整(但简单)的测试程序,它通过将 io 延迟到后台线程来实现异步 io。
the program will wait for you to enter strings (terminate with newline) on the console and then perform a 10-second operation with that string.
该程序将等待您在控制台上输入字符串(以换行符终止),然后对该字符串执行 10 秒的操作。
you can enter another string while the operation is in progress.
您可以在操作进行时输入另一个字符串。
enter 'quit' to get the program to stop on the next cycle.
输入 'quit' 使程序在下一个周期停止。
$ ./async.cpp
first
new string: first 0 1las 2t 3
4 5 6 7 8 9. done. next?
new string: last 0 1 2 3 4 5 6 7 8quit 9. done. next?
sample test run:
示例测试运行:
##代码##回答by Jeremy Friesner
The StdinDataIOclass of the BSD-licensed MUSCLE networking librarysupports non-blocking reads from stdin under Windows, MacOS/X, and Linux/Unix ... you could use that (or just examine the code as an example of how it can be done) if you want.
BSD 许可的MUSCLE 网络库的StdinDataIO类支持从 Windows、MacOS/X 和 Linux/Unix 下的 stdin 非阻塞读取......你可以使用它(或者只是检查代码作为它如何可以完成)如果你愿意。
回答by Unix-Ninja
You can use the tinycon library to do this. Just spawn a tinycon object in a new thread, and you are pretty much done. You can define the trigger method to fire off whatever you'd like when enter is pressed.
您可以使用 tinycon 库来执行此操作。只需在新线程中生成一个 tinycon 对象,就大功告成了。您可以定义触发方法以在按下 Enter 时触发您想要的任何内容。
You can find it here: https://sourceforge.net/projects/tinycon/
你可以在这里找到它:https: //sourceforge.net/projects/tinycon/
Also, the license is BSD, so it will be the most permissive for your needs.
此外,许可证是 BSD,因此它将最适合您的需求。