通过信号唤醒std::getline

Wake up std::getline through signal

我通过 std::getline()stdin 读取用户输入,我希望能够通过 SIGINT 退出程序。不幸的是,std::getline() 似乎没有被任何信号唤醒。因此,下面的代码仅在按下 CTRL-C and RETURN.

后中止
#include <csignal>
#include <string>
#include <iostream>

bool abort_ = false;

void SigIntHandler(int signum) {
  std::cout << "Received SIGINT" << std::endl;
  abort_ = true;
}


int main(int argc, char *argv[]) {
  signal(SIGINT, SigIntHandler);

  while (!abort_) {
    std::string line;

    std::cout << "> ";
    std::getline(std::cin, line);
    if (!std::cin)
      std::cin.clear();

    std::cout << line << std::endl;
  }
}

为什么会这样?除了用户输入,我还有机会唤醒 std::getline() 吗?或者是否有任何其他方法可以从 stdin 读取,也可以响应信号?

std::getline 和一般的 input/output 库在进程接收到信号时没有指定的行为。 C++ 库和语言未指定任何特定行为。信号只是顺便提及,最值得注意的参考仅是:

A call to the function signal synchronizes with any resulting invocation of the signal handler so installed.

这和头文件的枚举是 C++ 库中信号引用的总和。信号是一种高度特定于操作系统的功能,C++ 库根本没有涵盖它。

None 的 C++ 库函数和此处讨论的 类 是信号安全的。在显示的代码中,信号处理程序无法对输入流执行任何操作,因为它的内部状态是不确定的,并且整个过程都不​​是信号安全的。

因此,要处理信号,有必要求助于低级操作系统特定调用,如 open()read()write(),而不是使用C++ input/output 库。当然,其中一种选择是编写您自己的 std::streambuf 子类,使用低级系统调用实现其功能,并适当地处理信号。您自己的实现将通过将流缓冲区设置为失败状态(或者,也许模拟接收 ENTER 键,嘿,这是您的表演)并返回来适当地阻止输入和处理任何接收到的信号。