You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中拦截/恢复macOS终端resize系统调用?

在C++中处理macOS终端窗口调整对cin/read的干扰问题

macOS终端窗口调整大小时,系统会发送SIGWINCH信号,这个信号会直接中断处于阻塞状态的read()系统调用(cin底层就是靠它实现输入读取的),导致调用返回EINTR错误;而多数Linux发行版里,终端窗口调整不会触发这种中断,或者系统会自动重启被中断的调用,所以不会有问题。

你之前用sigfillset(&mask)屏蔽所有信号的做法,会把SIGINT(Ctrl+C触发的退出信号)也一起屏蔽,自然没法正常退出程序——完全没必要这么做,只需要针对SIGWINCH信号处理就行。

给你两种可行的解决思路:

1. 注册空的SIGWINCH处理函数

给SIGWINCH挂一个空的处理函数,这样系统收到这个信号时,就不会中断正在阻塞的read()调用,而是直接忽略(执行空函数后继续原来的调用)。

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

// 空的SIGWINCH信号处理函数
void sigwinch_handler(int) {}

int main() {
    struct sigaction sa;
    sa.sa_handler = sigwinch_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGWINCH, &sa, nullptr);

    char input_buf[1024];
    std::cout << "输入内容: ";
    ssize_t read_len = read(STDIN_FILENO, input_buf, sizeof(input_buf) - 1);
    
    if (read_len == -1) {
        perror("读取失败");
        return 1;
    }
    input_buf[read_len] = '\0';
    std::cout << "你输入了: " << input_buf << std::endl;

    return 0;
}

2. 手动重启被中断的读取操作

如果不想修改信号处理,也可以在read()返回EINTR错误时,手动重试读取操作——这是处理信号中断系统调用的标准做法。

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

int main() {
    char input_buf[1024];
    std::cout << "输入内容: ";
    ssize_t read_len;

    // 被信号中断就重试
    do {
        read_len = read(STDIN_FILENO, input_buf, sizeof(input_buf) - 1);
    } while (read_len == -1 && errno == EINTR);

    if (read_len == -1) {
        perror("读取失败");
        return 1;
    }
    input_buf[read_len] = '\0';
    std::cout << "你输入了: " << input_buf << std::endl;

    return 0;
}

针对cin的说明

cin是C++标准库封装的输入流,底层同样依赖read(),所以上面的第一种方案直接就能用;如果用第二种方案,你需要自己封装cin的读取逻辑,或者在cin触发failbit后检查错误原因,确认是EINTR的话清空错误状态并重试。

内容的提问来源于stack exchange,提问作者Massimo D'Ambrosio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:46:16