此问题基于以下问题: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 ,似乎进程总是被杀死:
A HandlerRoutine can perform any necessary cleanup, then take one of the following actions:
- Call the ExitProcess function to terminate the process.
- Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.
- Return TRUE. In this case, no other handler functions are called and the system terminates
流程。
我是否遗漏了一些明显的东西? 终止 win32 控制台进程并执行其清理代码的正确方法是什么?
最佳答案
这是一种方法,但我建议您使用事件 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 调试器运行它。当通知您如果安装了处理程序就可以继续时,只需选择“继续”即可。
关于c++ - Win32 控制台程序中的清理代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18774256/