从 cin 读取的进程上的 HUP 信号
HUP Signal on a process reading from cin
我有一个可执行文件,它总是在循环中从 std::cin 读取输入,我也有一个 SIGHUP 处理程序。
#include <iostream>
#include <signal.h>
void hupHandler(int)
{
std::cout << "Handled sighup" << std::endl;
}
int main(int, char*[])
{
struct sigaction sigHupHandler{};
sigHupHandler.sa_handler = hupHandler;
sigemptyset(&sigHupHandler.sa_mask);
sigHupHandler.sa_flags = 0;
sigaction(SIGHUP, &sigHupHandler, nullptr);
while(true)
{
std::string input;
std::getline(std::cin, input);
std::cout << "Read input \"" << input << "\"" << std::endl;
}
std::cout << "Child Exiting" << std::endl;
return 0;
}
当我在终端上启动可执行文件并使用 kill -HUP 发送 SIGHUP 时,我看到它处理了 SIGHUP,但之后我看到了以下无限打印 -
$ ./child
Handled sighup
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
有人可以向我解释一下这种行为吗?我实际上需要有一个在后台运行的进程并不断地监听它的标准输入(另一个进程提供给它的标准输入)。如果它已被 SIGHUP,我还需要它来重新加载配置。我注意到,一旦我 HUP 它就进入了一个读取空行的循环。所以我写了这个实用程序来测试,我看到了同样的行为。任何帮助将不胜感激,谢谢!
您不能在信号处理程序中随心所欲。信号处理程序可以随时 中断程序。包括在 C++ 库函数或 class 和 none 中执行某些操作时,C++ 库函数、模板等都是可重入的。您几乎不能在信号处理程序中使用任何 C++ 库代码,当然也不能 std::cout
。您甚至不能做 new
或 delete
任何事情。这是第一个问题,这里。
你也不能使用 C 库函数。它们也不是可重入的。您在信号处理程序中唯一可以做的就是使用操作系统调用,例如 open/close/read/write 等。 (基本上,手册页的第 2 节),直接。
因此,显示的代码是未定义的行为,您不能期望它以任何方式、形状、物质或形式可靠地工作,只要您的信号处理程序执行它所做的。
此外,当进程处于系统调用本身的中间时(取决于特定的系统调用),捕获的信号会导致特定 errno
为 EINTR
的失败。这在您的 signal(7)
手册页中有描述,您应该阅读它。 C++ 库很可能会将此解释为从文件中读取的任何其他错误,并将流设置为失败状态,这看起来就像您看到的行为。你也必须自己处理。
我有一个可执行文件,它总是在循环中从 std::cin 读取输入,我也有一个 SIGHUP 处理程序。
#include <iostream>
#include <signal.h>
void hupHandler(int)
{
std::cout << "Handled sighup" << std::endl;
}
int main(int, char*[])
{
struct sigaction sigHupHandler{};
sigHupHandler.sa_handler = hupHandler;
sigemptyset(&sigHupHandler.sa_mask);
sigHupHandler.sa_flags = 0;
sigaction(SIGHUP, &sigHupHandler, nullptr);
while(true)
{
std::string input;
std::getline(std::cin, input);
std::cout << "Read input \"" << input << "\"" << std::endl;
}
std::cout << "Child Exiting" << std::endl;
return 0;
}
当我在终端上启动可执行文件并使用 kill -HUP 发送 SIGHUP 时,我看到它处理了 SIGHUP,但之后我看到了以下无限打印 -
$ ./child
Handled sighup
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
Read input ""
有人可以向我解释一下这种行为吗?我实际上需要有一个在后台运行的进程并不断地监听它的标准输入(另一个进程提供给它的标准输入)。如果它已被 SIGHUP,我还需要它来重新加载配置。我注意到,一旦我 HUP 它就进入了一个读取空行的循环。所以我写了这个实用程序来测试,我看到了同样的行为。任何帮助将不胜感激,谢谢!
您不能在信号处理程序中随心所欲。信号处理程序可以随时 中断程序。包括在 C++ 库函数或 class 和 none 中执行某些操作时,C++ 库函数、模板等都是可重入的。您几乎不能在信号处理程序中使用任何 C++ 库代码,当然也不能 std::cout
。您甚至不能做 new
或 delete
任何事情。这是第一个问题,这里。
你也不能使用 C 库函数。它们也不是可重入的。您在信号处理程序中唯一可以做的就是使用操作系统调用,例如 open/close/read/write 等。 (基本上,手册页的第 2 节),直接。
因此,显示的代码是未定义的行为,您不能期望它以任何方式、形状、物质或形式可靠地工作,只要您的信号处理程序执行它所做的。
此外,当进程处于系统调用本身的中间时(取决于特定的系统调用),捕获的信号会导致特定 errno
为 EINTR
的失败。这在您的 signal(7)
手册页中有描述,您应该阅读它。 C++ 库很可能会将此解释为从文件中读取的任何其他错误,并将流设置为失败状态,这看起来就像您看到的行为。你也必须自己处理。