Select 计划一个异步事件,该事件将在stdin在boost::asio中有等待数据时完成?
我将boost::asio与ncurses一起用于命令行游戏。游戏需要以固定的时间间隔在屏幕上绘制,必要时也会执行其他操作(如网络或文件操作)。所有这些事情都可以通过boost::asio上的Select 计划一个异步事件,该事件将在stdin在boost::asio中有等待数据时完成?,select,boost,boost-asio,stdin,ncurses,Select,Boost,Boost Asio,Stdin,Ncurses,我将boost::asio与ncurses一起用于命令行游戏。游戏需要以固定的时间间隔在屏幕上绘制,必要时也会执行其他操作(如网络或文件操作)。所有这些事情都可以通过boost::asio上的async\u read()/async\u write()或等效工具来完成 然而,我还需要读取键盘输入,我认为它来自标准输入法。在ncurses中读取输入的常用方法是调用getch(),可以将其配置为阻塞(等待有字符可供使用)或非阻塞(返回无字符可用的sentinel值)模式 使用阻塞模式将需要在单独的线
async\u read()
/async\u write()
或等效工具来完成
然而,我还需要读取键盘输入,我认为它来自标准输入法。在ncurses中读取输入的常用方法是调用getch()
,可以将其配置为阻塞(等待有字符可供使用)或非阻塞(返回无字符可用的sentinel值)模式
使用阻塞模式将需要在单独的线程上运行getch()
,这对ncurses不起作用。然而,使用非阻塞模式会导致我的应用程序在循环中消耗CPU时间,直到用户按下键盘。我已经阅读了答案,它建议我们可以在select()
调用中将stdin
添加到文件描述符列表中,直到其中一个文件描述符有新数据为止
因为我使用的是boost::asio,所以不能直接使用
select()
。我无法调用async\u read
,因为这将消耗字符,使getch()
无需读取。boost::asio中是否有类似于async\u read
,但只检查输入的存在而不使用它?我认为您应该能够使用posix流描述符来监视文件描述符0
上的输入:
ba::posix::stream_descriptor d(io, 0);
input_loop = [&](error_code ec) {
if (!ec) {
program.on_input();
d.async_wait(ba::posix::descriptor::wait_type::wait_read, input_loop);
}
};
在那里,program::on_input()
将调用getch()
,无timeout()
,直到返回ERR
:
struct Program {
Program() {
initscr();
ESCDELAY = 0;
timeout(0);
cbreak();
noecho();
keypad(stdscr, TRUE); // receive special keys
clock = newwin(2, 40, 0, 0);
monitor = newwin(10, 40, 2, 0);
syncok(clock, true); // automatic updating
syncok(monitor, true);
scrollok(monitor, true); // scroll the input monitor window
}
~Program() {
delwin(monitor);
delwin(clock);
endwin();
}
void on_clock() {
wclear(clock);
char buf[32];
time_t t = time(NULL);
if (auto tmp = localtime(&t)) {
if (strftime(buf, sizeof(buf), "%T", tmp) == 0) {
strncpy(buf, "[error formatting time]", sizeof(buf));
}
} else {
strncpy(buf, "[error getting time]", sizeof(buf));
}
wprintw(clock, "Async: %s", buf);
wrefresh(clock);
}
void on_input() {
for (auto ch = getch(); ch != ERR; ch = getch()) {
wprintw(monitor, "received key %d ('%c')\n", ch, ch);
}
wrefresh(monitor);
}
WINDOW *monitor = nullptr;
WINDOW *clock = nullptr;
};
使用以下main
程序,您可以运行它10秒钟(因为program
还不知道如何退出):
intmain(){
程序;
名称空间ba=boost::asio;
使用boost::system::error\u代码;
使用名称空间std::literals;
ba::io_服务io;
std::功能输入环路、时钟环路;
//在标准输入上准备就绪时读取输入
ba::posix::流描述符d(io,0);
输入循环=[&](错误代码ec){
如果(!ec){
program.on_input();
d、 异步等待(ba::posix::描述符::等待类型::等待读取,输入循环);
}
};
//为了好玩,让我们也更新一下时间
ba:高分辨率定时器tim(io);
时钟循环=[&](错误代码ec){
如果(!ec){
program.on_clock();
tim.从现在起过期(100ms);
异步等待(时钟循环);
}
};
输入循环(错误代码{});
时钟循环(错误代码{});
io.运行(10秒);
}
这项工作:
完整列表
#包括
#包括
#包括
#包括“ncurses.h”
#定义CTRL\u R 18
#定义CTRL\U C 3
#定义选项卡9
#定义换行符10
#定义返回13
#定义逃逸27
#定义退格127
#定义最多72个
#定义左75
#定义权利77
#下定义80
结构程序{
程序(){
initscr();
ESCDELAY=0;
超时(0);
cbreak();
noecho();
键盘(stdscr,TRUE);//接收特殊键
时钟=纽温(2,40,0,0);
monitor=newwin(10,40,2,0);
syncok(时钟,真);//自动更新
syncok(监视器,真);
scrollok(监视器,true);//滚动输入监视器窗口
}
~Program(){
德尔温(班长);
德尔温(时钟);
endwin();
}
在时钟()上无效{
wclear(时钟);
char-buf[32];
时间t=时间(空);
if(自动tmp=localtime(&t)){
if(strftime(buf,sizeof(buf),“%T”,tmp)==0){
strncpy(buf,“[错误格式化时间]”,sizeof(buf));
}
}否则{
strncpy(buf,“[获取时间时出错]”,sizeof(buf));
}
wprintw(时钟,“异步:%s”,buf);
(时钟);
}
输入时无效(){
for(auto ch=getch();ch!=ERR;ch=getch()){
wprintw(监视器,“已接收密钥%d(“%c”)\n”,ch,ch);
}
新鲜水(监测);;
}
窗口*监视器=空PTR;
窗口*时钟=空PTR;
};
int main(){
程序;
名称空间ba=boost::asio;
使用boost::system::error\u代码;
使用名称空间std::literals;
ba::io_服务io;
std::功能输入环路、时钟环路;
//在标准输入上准备就绪时读取输入
ba::posix::流描述符d(io,0);
输入循环=[&](错误代码ec){
如果(!ec){
program.on_input();
d、 异步等待(ba::posix::描述符::等待类型::等待读取,输入循环);
}
};
//为了好玩,让我们也更新一下时间
ba:高分辨率定时器tim(io);
时钟循环=[&](错误代码ec){
如果(!ec){
program.on_clock();
tim.从现在起过期(100ms);
异步等待(时钟循环);
}
};
输入循环(错误代码{});
时钟循环(错误代码{});
io.运行(10秒);
}
这似乎在这里起作用,我没有意识到boost::asio::posix::stream\u descriptor
hadasync\u wait()
。对于Windows,我使用了boost::asio::Windows::object\u handle(ctx,GetStdHandle(STD\u INPUT\u handle))
,它有一个类似的async\u wait()
函数。在较旧的Boost版本中,存在仍然需要async\u读取
或async\u写入
。因此,新的界面显然更好(据我所知,这是网络TS的一部分)
int main() {
Program program;
namespace ba = boost::asio;
using boost::system::error_code;
using namespace std::literals;
ba::io_service io;
std::function<void(error_code)> input_loop, clock_loop;
// Reading input when ready on stdin
ba::posix::stream_descriptor d(io, 0);
input_loop = [&](error_code ec) {
if (!ec) {
program.on_input();
d.async_wait(ba::posix::descriptor::wait_type::wait_read, input_loop);
}
};
// For fun, let's also update the time
ba::high_resolution_timer tim(io);
clock_loop = [&](error_code ec) {
if (!ec) {
program.on_clock();
tim.expires_from_now(100ms);
tim.async_wait(clock_loop);
}
};
input_loop(error_code{});
clock_loop(error_code{});
io.run_for(10s);
}
#include <boost/asio.hpp>
#include <boost/asio/posix/descriptor.hpp>
#include <iostream>
#include "ncurses.h"
#define CTRL_R 18
#define CTRL_C 3
#define TAB 9
#define NEWLINE 10
#define RETURN 13
#define ESCAPE 27
#define BACKSPACE 127
#define UP 72
#define LEFT 75
#define RIGHT 77
#define DOWN 80
struct Program {
Program() {
initscr();
ESCDELAY = 0;
timeout(0);
cbreak();
noecho();
keypad(stdscr, TRUE); // receive special keys
clock = newwin(2, 40, 0, 0);
monitor = newwin(10, 40, 2, 0);
syncok(clock, true); // automatic updating
syncok(monitor, true);
scrollok(monitor, true); // scroll the input monitor window
}
~Program() {
delwin(monitor);
delwin(clock);
endwin();
}
void on_clock() {
wclear(clock);
char buf[32];
time_t t = time(NULL);
if (auto tmp = localtime(&t)) {
if (strftime(buf, sizeof(buf), "%T", tmp) == 0) {
strncpy(buf, "[error formatting time]", sizeof(buf));
}
} else {
strncpy(buf, "[error getting time]", sizeof(buf));
}
wprintw(clock, "Async: %s", buf);
wrefresh(clock);
}
void on_input() {
for (auto ch = getch(); ch != ERR; ch = getch()) {
wprintw(monitor, "received key %d ('%c')\n", ch, ch);
}
wrefresh(monitor);
}
WINDOW *monitor = nullptr;
WINDOW *clock = nullptr;
};
int main() {
Program program;
namespace ba = boost::asio;
using boost::system::error_code;
using namespace std::literals;
ba::io_service io;
std::function<void(error_code)> input_loop, clock_loop;
// Reading input when ready on stdin
ba::posix::stream_descriptor d(io, 0);
input_loop = [&](error_code ec) {
if (!ec) {
program.on_input();
d.async_wait(ba::posix::descriptor::wait_type::wait_read, input_loop);
}
};
// For fun, let's also update the time
ba::high_resolution_timer tim(io);
clock_loop = [&](error_code ec) {
if (!ec) {
program.on_clock();
tim.expires_from_now(100ms);
tim.async_wait(clock_loop);
}
};
input_loop(error_code{});
clock_loop(error_code{});
io.run_for(10s);
}