gpt4 book ai didi

select - 安排一个异步事件,当 stdin 在 boost::asio 中有等待数据时将完成?

转载 作者:行者123 更新时间:2023-12-04 10:53:35 26 4
gpt4 key购买 nike

我正在将 boost::asio 与 ncurses 一起用于命令行游戏。游戏需要以固定的时间间隔在屏幕上绘制,其他操作(例如联网或文件操作)也会在必要时执行。所有这些事情都可以通过 async_read() 来完成/async_write()或 boost::asio 上的等效项。

但是,我还需要读取键盘输入,(我认为)来自 stdin。在 ncurses 中读取输入的常用方法是调用 getch() ,它可以配置为阻塞(等待直到有可用字符消费)或非阻塞(返回没有可用字符的标记值)模式。

使用阻塞模式需要运行 getch()在一个单独的线程上,它不能很好地与 ncurses 配合使用。但是,使用非阻塞模式会导致我的应用程序在循环中消耗 CPU 时间,直到用户按下键盘。我已阅读 this答案,这表明我们可以添加 stdinselect() 中的文件描述符列表调用,它将阻塞,直到其中一个文件描述符有新数据。

由于我使用的是 boost::asio,所以不能直接使用 select() .我打不通 async_read ,因为这会消耗字符,留下 getch()没有什么可读的。 boost::asio 中是否有类似 async_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 还不知道如何退出):
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);
}

这有效:

enter image description here

完整列表
#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);
}

关于select - 安排一个异步事件,当 stdin 在 boost::asio 中有等待数据时将完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59341959/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com