如何在C/C++中检测进程是否处于终止阶段?
如何检测C/C++应用是否处于进程终止阶段?
在C/C应用中,进程终止阶段会执行大量代码,比如atexit()注册的处理程序、带析构函数的全局C对象,以及C++11及以后带析构函数的thread_local复杂类型对象。我们需要实现一个类似如下的函数来检测应用是否正在退出:
/// returns 1 if the application is in the process of exit()-ing extern int is_shutting_down();
由于代码运行在通过dlopen()加载的共享库中,无法控制主程序的退出时机,因此无法通过在main()返回或调用exit()前设置全局变量的常规方式实现。以下是可行的实现方案:
一、可移植方案
基于atexit()的标记方案
利用atexit()注册的处理程序会在进程正常退出(main()返回或调用exit())时按逆序执行的特性,在共享库加载时自动注册一个标记函数,进程退出时该函数会被触发并设置全局标志。
代码示例:
#include <stdlib.h> // 用volatile避免编译器优化读写操作 static volatile int shutting_down = 0; static void mark_shutting_down() { shutting_down = 1; } // 共享库加载时自动执行构造函数,完成atexit注册 __attribute__((constructor)) void init_shutdown_detector() { atexit(mark_shutting_down); } int is_shutting_down() { return shutting_down; }
注意:
- 该方案无法检测
_exit()/_Exit()直接终止进程的情况(这类函数不会执行清理逻辑) - 无法处理信号导致的异常终止(如SIGKILL)
二、平台专属方案
Linux 平台
在可移植方案基础上,增加对常见终止信号的处理,覆盖更多退出场景:
#include <stdlib.h> #include <signal.h> static volatile sig_atomic_t shutting_down = 0; static void mark_shutting_down() { shutting_down = 1; } static void sig_handler(int sig) { // 异步安全地设置标志,然后恢复默认信号处理逻辑 shutting_down = 1; signal(sig, SIG_DFL); raise(sig); } __attribute__((constructor)) void init_shutdown_detector() { atexit(mark_shutting_down); // 注册常见终止信号的处理函数 signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGQUIT, sig_handler); } int is_shutting_down() { return shutting_down; }
Windows 平台
利用Windows的DLL生命周期回调和控制台控制事件处理,覆盖进程退出的多种场景:
#include <windows.h> #include <stdlib.h> // 用原子操作保证多线程环境下的变量安全 static volatile LONG shutting_down = 0; static void mark_shutting_down() { InterlockedExchange(&shutting_down, 1); } static BOOL WINAPI console_ctrl_handler(DWORD ctrl_type) { switch (ctrl_type) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: InterlockedExchange(&shutting_down, 1); return FALSE; // 让系统执行默认终止逻辑 default: return FALSE; } } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: onexit(mark_shutting_down); SetConsoleCtrlHandler(console_ctrl_handler, TRUE); break; case DLL_PROCESS_DETACH: // DLL卸载时,进程必然处于退出阶段 InterlockedExchange(&shutting_down, 1); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; } int is_shutting_down() { return InterlockedCompareExchange(&shutting_down, 0, 0); }
macOS 平台
类似Linux方案,结合atexit()和信号处理实现:
#include <stdlib.h> #include <signal.h> static volatile sig_atomic_t shutting_down = 0; static void mark_shutting_down() { shutting_down = 1; } static void sig_handler(int sig) { shutting_down = 1; signal(sig, SIG_DFL); raise(sig); } __attribute__((constructor)) void init_shutdown_detector() { atexit(mark_shutting_down); signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGQUIT, sig_handler); } int is_shutting_down() { return shutting_down; }
三、通用注意事项
- 所有方案均无法检测
_exit()/_Exit()直接终止的情况,这类操作会跳过所有清理逻辑 - 信号处理函数必须保证异步安全,不能调用如
printf这类非异步安全的函数 - 全局标志的读写需保证线程安全,必要时使用原子操作或
volatile关键字
内容的提问来源于stack exchange,提问作者Wenzel Jakob
相关产品推荐
相关产品推荐

