ncurses阻塞模式下getch()被SIGALRM信号中断返回问题咨询
问题根本原因
- POSIX 系统中,阻塞状态的慢速系统调用(
wgetch底层依赖的终端读取read调用就属于这类)在收到未设置SA_RESTART标志的信号时,会被强制中断返回,返回值为-1,同时errno被设置为EINTR。 - 你注册 SIGALRM 信号处理函数时未开启
SA_RESTART标志,每次定时器触发信号、处理函数执行完成后,正在阻塞的wgetch就会被中断,返回ERR(ncurses 定义的错误常量,通常值为-1)。 - 你的代码没有对
wgetch的返回值做合法性校验,无论返回的是有效按键还是中断错误,都会执行total_keys++逻辑,就会出现定时器触发时计数异常递增的现象。
修复方案
- 方案一:注册信号处理函数时添加
SA_RESTART标志。配置sigaction结构体时,给sa_flags字段追加SA_RESTART,该参数会让被信号中断的系统调用在信号处理结束后自动重启,wgetch会继续保持阻塞等待按键,不会提前返回:
struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_sigaction = alarm_handler; // 原有SA_SIGINFO保留,追加SA_RESTART sa.sa_flags = SA_SIGINFO | SA_RESTART; sigaction(SIGALRM, &sa, NULL);
- 方案二:在
wgetch返回后增加返回值校验,仅当返回值为有效按键时才执行计数和处理逻辑:
int total_keys = 0; while (1) { inputchar = wgetch(mywindow); // 被信号中断返回ERR时,跳过后续逻辑继续等待输入 if (inputchar == ERR) continue; mvprintw(LINES - 2, 2, "%d", total_keys++); refresh(); switch (inputchar) { ... } }
内容的提问来源于stack exchange,提问作者JonPC
相关产品推荐
相关产品推荐

