我正在寻找一种(多平台)方式来为我的C ++程序执行非阻塞控制台输入,因此我可以在程序不断运行时处理用户命令。该计划还将同时输出信息。
最好/最简单的方法是什么?只要他们使用许可许可,我就可以使用像boost这样的外部库。
答案 0 :(得分:9)
我会通过创建一个单独的线程来执行此操作,该线程调用正常的阻塞IO函数并向其传递一个回调函数,它在输入时会调用它。你确定你需要做你想说的事吗?
至于同时输出信息,如果用户正在输入一些输入并且你打印了什么内容会发生什么?
答案 1 :(得分:4)
我在QNX4.5上使用select
不支持线程或Boost。您基本上将select
STDIN作为要使用的文件描述符传递,并且选择将在输入新行时返回。我在下面添加了一个简化的示例循环。它是独立于平台的,至少对于类似Unix的系统而言。虽然不确定Windows。
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);
}
}
}
答案 2 :(得分:4)
有一种简单的方法:
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] = '\0';
point = 0;
//Run(buffer);
}
}
没有阻止,全部在1个线程中。至于我,这很有效。
答案 3 :(得分:4)
使用C ++ 11的示例:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
static std::string getAnswer()
{
std::string answer;
std::cin >> answer;
return answer;
}
int main()
{
int timeout = 5;
std::cout << "do you even lift?" << std::endl;
std::string answer = "maybe"; //default to maybe
std::future<std::string> future = std::async(getAnswer);
if (future.wait_for(std::chrono::seconds(timeout)) == std::future_status::ready)
answer = future.get();
std::cout << "the answer was: " << answer << std::endl;
exit(0);
}
答案 4 :(得分:3)
非阻塞控制台输入C ++?
Ans:在后台线程上执行控制台IO,并提供线程之间的通信方式。
这是一个完整(但简单化)的测试程序,它通过将io推迟到后台线程来实现async io。
程序将等待您在控制台上输入字符串(以换行符终止),然后使用该字符串执行10秒操作。
您可以在操作过程中输入另一个字符串。
输入'quit'以使程序在下一个周期停止。
#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;
}
样品测试运行:
$ ./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?
答案 5 :(得分:2)
ncurses可能是一个很好的候选人。
答案 6 :(得分:0)
BSD许可StdinDataIO的MUSCLE networking library类支持Windows,MacOS / X和Linux / Unix下stdin的非阻塞读取...你可以使用它(或者只是检查一下)代码作为如何做的一个例子)如果你想要。
答案 7 :(得分:0)
您可以使用tinycon库来执行此操作。只是在一个新线程中生成一个tinycon对象,你就完成了。您可以定义触发方法,以便在按下输入时触发您想要的任何内容。
你可以在这里找到它: https://sourceforge.net/projects/tinycon/
此外,许可证是BSD,因此它将是您最需要的许可。
答案 8 :(得分:0)
libuv是用于异步I / O的跨平台C库。它使用事件循环来执行诸如从标准输入读取而不阻塞线程的操作。 libuv是Node.JS和其他人的强大之处。