1. 程式人生 > >linux c開發: 在程序退出時進行處理

linux c開發: 在程序退出時進行處理

ack 自己 main class ctr ace its func 語言

有時候,希望程序退出時能進行一些處理,比如保存狀態,釋放一些資源。c語言開發的linux程序,有可能正常退出(exit),有可能異常crash,而異常crash可能是響應了某信號的默認處理。這裏總結一下這些情況,如何獲取一個統一的退出處理的點,說白了就是寫一個回調函數,讓他在程序正常或異常退出時調用。

  • 先看正常退出,即調用exit或者main函數return亦或最後一個線程正常退出時,如何捕獲退出事件。
    使用atexit函數。頭文件:#include<stdlib.h>, 函數原型:void atexit(void (*func)(void));
    atexit可以調用多次,註冊多個回調函數,在進程退出時調用,同一個函數可以被註冊多次。使用示例:
void server_on_exit(void)
{
    //do something when process exits
}
int main(int argc, char *argv[])
{
    atexit(server_on_exit);

    return 0;
}

  

  • 再看異常退出,如abort,響應某些signal的默認處理是異常退出,還有直接kill進程。
    處理方法是使用signal函數,註冊自己的回調函數,而避免系統默認的回調,系統默認的回調可能就是直接crash掉程序。使用例子:
#include <signal.h>
void signal_crash_handler(int sig)
{
    server_backtrace(sig);
    exit(-1);
}

void signal_exit_handler(int sig)
{
    exit(0);
}

int main(int argc, char *argv[])
{
    atexit(server_on_exit);
    signal(SIGTERM, signal_exit_handler);
    signal(SIGINT, signal_exit_handler);

    // ignore SIGPIPE
    signal(SIGPIPE, SIG_IGN);

    signal(SIGBUS, signal_crash_handler);     // 總線錯誤
    signal(SIGSEGV, signal_crash_handler);    // SIGSEGV,非法內存訪問
    signal(SIGFPE, signal_crash_handler);       // SIGFPE,數學相關的異常,如被0除,浮點溢出,等等
    signal(SIGABRT, signal_crash_handler);     // SIGABRT,由調用abort函數產生,進程非正常退出

    return 0;
}

  

這個例子裏面其實是將異常退出處理和正常退出處理結合起來了。對於SIGTERM(即kill進程)和SIGINT(即ctrl-c結束前臺進程),我們當做是正常退出,在其信號處理函數裏面,直接調用了exit(0),而exit(0)又會被server_on_exit捕獲到。對於異常退出也是類似,只是調用了exit(-1)表示是異常的。同時異常退出我們會打印出當前的進程堆棧信息,server_backtrace的實現下一篇再說。另外註意的是SIGKILL信號是無法捕獲的。而調用abort導致的退出,也是通過SIGABRT信號捕獲到進行處理了。其他幾種異常退出的信號也是比較常見,一並捕獲到進行處理。這樣對於異常退出,我們即可統一的log堆棧信息,又可直接繼續正常退出時的處理流程了。

linux c開發: 在程序退出時進行處理