此问题基于以下问题:Handle CTRL+C on Win32
我正在研究在Linux和Windows上运行的多线程服务器。我不能使用boost或其他框架,只能使用std c ++。
我在win32端的清理代码有问题。 linux方面运行正常:当我想关闭服务器时,我发送SIGINT
(带CTRL+C
),信号处理程序设置一个全局变量,主pthread执行清理指令(加入其他pthreads) ,释放堆内存等。)。
在Windows上,获得相同的行为看起来并不那么简单。 我编写了一个简单的测试程序来了解信号处理程序如何在Windows中运行。
#include <iostream>
#include <windows.h>
bool running;
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = false;
std::cout << "[CTRL+C]\n";
return TRUE;
}
return FALSE;
}
int main(int argc, char **argv) {
running = true;
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
std::cerr << "Error: " << GetLastError() << '\n';
return -1;
}
std::cout << "Main thread working hard...\n";
while (running) { ; }
for (int i = 0; i < 20; i++)
std::cout << "This is the " << i << "th fake cleanup instruction\n";
return 0;
}
输出如下:
$ test.exe
Main thread working hard...
[CTRL+C]
This is the 0th fake cleanup instruction
This is the 1th fake cleanup instruction
因此主线程很快被杀死,只有在两条指令之后。在上一个问题中,one of the suggestion是在处理程序中移动清理代码,但实际上没有帮助:
假设处理函数看起来像这样:
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = false;
std::cout << "[CTRL+C]\n";
for (int i = 0; i < 20; i++)
std::cout << "This is the " << i << "th fake cleanup instruction\n";
return TRUE;
}
return FALSE;
}
现在行为更糟!输出是:
$ test.exe
Main thread working hard...
[CTRL+C]
This is the
根据MSDN,似乎该过程总是被杀死:
HandlerRoutine可以执行任何必要的清理,然后执行其中一个 以下行动:
- 调用ExitProcess函数以终止进程。
- 返回FALSE。如果没有注册的处理程序函数返回TRUE,则默认处理程序将终止该进程。
- 返回TRUE。在这种情况下,不会调用其他处理函数,系统将终止
这个过程。
我错过了一些明显的东西吗? 终止win32控制台进程和执行清理代码的正确方法是什么?
答案 0 :(得分:3)
这是一种方法,虽然我建议你使用事件HANDLE和WaitForSingleObject,因为它往往会更加“屈服”。我在这里留下了高速自旋循环,只是为了你固定你的一个核心,同时仍然看到处理程序被截获。
我冒昧地修改你的运行状态,分别进行原子评估和设置,因为我不希望优化器在主循环中抛出eval。
#include <iostream>
#include <cstdlib>
#include <windows.h>
// using an event for monitoring
LONG running = 1;
BOOL WINAPI consoleHandler(DWORD signal)
{
if (signal == CTRL_C_EVENT)
{
std::out << "Received Ctrl-C; shutting down..." << std::endl;
InterlockedExchange(&running, 0);
return TRUE;
}
return FALSE;
}
int main(int argc, char **argv)
{
if (!SetConsoleCtrlHandler(consoleHandler, TRUE))
{
std::cerr << "Error: " << GetLastError() << '\n';
return EXIT_FAILURE;
}
std::cout << "Main thread working hard...\n";
while (InterlockedCompareExchange(&running, 0, 0) == 1);
std::cout << "Graceful shutdown received. Shutting down now." << std::endl;
return 0;
}
输出(注意:我按了ctrl-C,以防它不明显)
Main thread working hard...
Received Ctrl-C; shutting down...
Graceful shutdown received. Shutting down now.
注意:我在64位和32位进程的调试和版本中对此进行了测试,没有任何问题。你可以从VS调试器运行它。只要选择“继续”,如果您安装了处理程序,则可以继续选择“继续”。
答案 1 :(得分:2)
在Windows上,您也可以使用信号处理程序:
static void shutdown(int signum)
{
printf("got signal #%d, terminating\n", signum);
// cleanup
_exit(1);
}
signal(SIGINT, shutdown);
signal(SIGTERM, shutdown);
signal(SIGSEGV, shutdown);
Ctrl-C映射到SIGINT
,就像在Linux上一样。
然而,这不会使用鼠标来处理关闭控制台窗口的用户。