You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:20:12