亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C/C++實現(xiàn)捕獲所有信號的示例詳解

 更新時間:2024年03月08日 16:15:26   作者:初級代碼游戲  
Linux的信號機制大部分情況下用不到,但是由于大部分信號的默認處理是終止進程,不正確處理會惹麻煩,所以我們來看看如何使用C/C++實現(xiàn)捕獲所有信號吧

一、原理

Linux的信號可能在你無法意識到的情況下發(fā)生。

比如socket網(wǎng)絡斷開,默認情況下發(fā)送SIGPIPE給正在send/recv的進程從而殺死進程,忘記了處理這個就很麻煩,程序大部分時間很正常,偶爾奇怪地終止,可能要花很大力氣才會找到原因。

而Linux的信號是不帶任何數(shù)據(jù)的,知道一個連接斷開又能怎么樣呢?又不知道是哪個連接斷開(其實我們會根據(jù)send/recv的返回值處理的嘛)。

所以為了省力,我們可以在程序開始處捕獲所有信號,然后再根據(jù)實際運行時的情況針對性處理(大部分情況根本不需要任何處理)。

關于信號的更多知識在后面的“信號描述”函數(shù)里。

二、基礎

處理信號最簡單的方式就是調(diào)用signal函數(shù),這個函數(shù)設置信號處理方法并返回之前的信號處理方法(以便你可以在執(zhí)行自己的處理之前或之后調(diào)用原來的處理方法從而形成調(diào)用鏈)。

       #include <signal.h>
 
       typedef void (*sighandler_t)(int);
 
       sighandler_t signal(int signum, sighandler_t handler);

signal還有幾種形式,不過這種最簡單了。 

三、代碼

捕獲全部信號的代碼

    int __all_sig_catch(int argc, char ** argv, int fun(int, char **))
    {
        signal(SIGABRT, sig_default);
        signal(SIGALRM, sig_default);
        signal(SIGBUS, sig_default);
        signal(SIGCHLD, sig_default);
        signal(SIGCONT, sig_default);
        signal(SIGFPE, sig_default);
        signal(SIGHUP, sig_default);
        signal(SIGILL, sig_default);
        //signal(SIGINT, sig_default);//ctrl-c
        signal(SIGIO, sig_default);
        signal(SIGIOT, sig_default);
        signal(SIGKILL, sig_default);
        signal(SIGPIPE, sig_default);
        signal(SIGPOLL, sig_default);
        signal(SIGPROF, sig_default);
        signal(SIGPWR, sig_default);
        signal(SIGQUIT, sig_default);
        signal(SIGSEGV, sig_default);
        signal(SIGSTOP, sig_default);
        signal(SIGSYS, sig_default);
        signal(SIGTERM, sig_default);
        signal(SIGTRAP, sig_default);
        signal(SIGTSTP, sig_default);
        signal(SIGTTIN, sig_default);
        signal(SIGTTOU, sig_default);
        signal(SIGURG, sig_default);
        signal(SIGUSR1, sig_default);
        signal(SIGUSR2, sig_default);
        signal(SIGVTALRM, sig_default);
        signal(SIGWINCH, sig_default);
        signal(SIGXCPU, sig_default);
        signal(SIGXFSZ, sig_default);
 
        int ret;
        try
        {
            ret = fun(argc, argv);
        }
        catch (...)
        {
            thelog << "未處理的異常發(fā)生" << ende;
            return __LINE__;
        }
        return ret;
    }

這個函數(shù)的調(diào)用方式是給main函數(shù)套一層殼,當然你也可以把參數(shù)都去掉,只保留設置信號處理函數(shù)的那部分。

SIGINT沒有捕獲,這是ctrl-c產(chǎn)生的信號,我確實需要這樣結(jié)束程序。

最后還捕獲了一下未處理的異常,這也是經(jīng)常疏忽的部分。如果需要生成core文件,可以調(diào)用abort()。

注意SIGKILL和SIGSTOP是無法捕獲的(雖然上面代碼里面有)。

調(diào)用代碼

int _main(int argc, char ** argv)
{
    ......
}
int main(int argc, char ** argv)
{
    return __all_sig_catch(argc, argv, _main);
}

信號處理函數(shù)

sig_default是設置的信號處理函數(shù),必須符合signal函數(shù)的要求:

    extern "C" void sig_default(int sig)
    {
        signal(sig, sig_default);
        cout << "pid=" << getpid() << " " << sigstr(sig) << endl;
    }

注意必須是extern "C",代碼里再次調(diào)用了signal設置信號處理函數(shù),這么做的原因我現(xiàn)在不是很確定,不過這么做起碼應該不會有什么問題。

嚴格說應該調(diào)用一下之前的處理函數(shù)的,不過這樣就會很復雜。因為我們在main函數(shù)開始處設置,所有信號應該是還沒有被設置過的。

信號描述

sigstr是輸出信號名稱的函數(shù):

    //信號的描述
    char const * sigstr(long sig)
    {
        switch(sig)
        {
        case SIGABRT    :    return "SIGABRT    進程調(diào)用abort函數(shù),進程非正常退出";
        case SIGALRM    :    return "SIGALRM    用alarm函數(shù)設置的timer超時或setitimer函數(shù)設置的interval timer超時";
        case SIGBUS     :    return "SIGBUS     某種特定的硬件異常,通常由內(nèi)存訪問引起";
        case SIGCHLD    :    return "SIGCHLD    子進程Terminate或Stop";
        case SIGCONT    :    return "SIGCONT    從stop中恢復運行";
#ifndef _LINUXOS
        case SIGEMT     :    return "SIGEMT     和實現(xiàn)相關的硬件異常";
#endif
        case SIGFPE     :    return "SIGFPE     數(shù)學相關的異常,如被0除,浮點溢出,等等";
        case SIGHUP     :    return "SIGHUP     終端斷開";
        case SIGILL     :    return "SIGILL     非法指令異常";
            //case SIGINFO    :    return "SIGINFO    BSD signal。由Status Key產(chǎn)生,通常是CTRL+T。發(fā)送給所有Foreground Group的進程     ";
        case SIGINT     :    return "SIGINT     由Interrupt Key產(chǎn)生,通常是CTRL+C或者DELETE";
        case SIGIO      :    return "SIGIO      異步IO事件";
            //case SIGIOT     :    return "SIGIOT     實現(xiàn)相關的硬件異常,一般對應SIGABRT                                              ";
        case SIGKILL    :    return "SIGKILL    強制中止";
        case SIGPIPE    :    return "SIGPIPE    在reader中止之后寫Pipe的時候發(fā)送";
            //case SIGPOLL    :    return "SIGPOLL    當某個事件發(fā)送給Pollable Device的時候發(fā)送                                        ";
        case SIGPROF    :    return "SIGPROF    Setitimer指定的Profiling Interval Timer所產(chǎn)生";
        case SIGPWR     :    return "SIGPWR     和系統(tǒng)相關。和UPS相關。";
        case SIGQUIT    :    return "SIGQUIT    輸入Quit Key(CTRL+\\)";
        case SIGSEGV    :    return "SIGSEGV    非法內(nèi)存訪問";
        case SIGSTOP    :    return "SIGSTOP    中止進程";
        case SIGSYS     :    return "SIGSYS     非法系統(tǒng)調(diào)用";
        case SIGTERM    :    return "SIGTERM    請求中止進程,kill命令缺省發(fā)送";
        case SIGTRAP    :    return "SIGTRAP    實現(xiàn)相關的硬件異常。一般是調(diào)試異常";
        case SIGTSTP    :    return "SIGTSTP    Suspend Key,一般是Ctrl+Z";
        case SIGTTIN    :    return "SIGTTIN    當Background Group的進程嘗試讀取Terminal的時候發(fā)送";
        case SIGTTOU    :    return "SIGTTOU    當Background Group的進程嘗試寫Terminal的時候發(fā)送";
        case SIGURG     :    return "SIGURG     當out-of-band data接收的時候可能發(fā)送";
        case SIGUSR1    :    return "SIGUSR1    用戶自定義signal 1";
        case SIGUSR2    :    return "SIGUSR2    用戶自定義signal 2";
        case SIGVTALRM  :    return "SIGVTALRM  setitimer函數(shù)設置的Virtual Interval Timer超時的時候";
        case SIGWINCH   :    return "SIGWINCH   當Terminal的窗口大小改變的時候,發(fā)送給Foreground Group的所有進程";
        case SIGXCPU    :    return "SIGXCPU    當CPU時間限制超時的時候";
        case SIGXFSZ    :    return "SIGXFSZ    進程超過文件大小限制";
        default:             return "未知的信號";
        }
    }

其中屏蔽掉了一些是因為兼容性問題(這段代碼以前要在IBM、SUN、HP的小型機上運行,后來才改在Linux上運行),你可以根據(jù)需要添加。

到此這篇關于C/C++實現(xiàn)捕獲所有信號的示例詳解的文章就介紹到這了,更多相關C++捕獲所有信號內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++異常使用詳解(看這一篇就夠了)

    C++異常使用詳解(看這一篇就夠了)

    C++中的異常是指在程序執(zhí)行過程中發(fā)生錯誤,導致程序無法正常運行的情況,下面這篇文章主要給大家介紹了關于C++異常使用的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • [c++]變量聲明與定義的規(guī)則詳解

    [c++]變量聲明與定義的規(guī)則詳解

    這篇文章主要介紹了[c++]變量聲明與定義的規(guī)則詳解,對于學習c++的朋友來說這是一個很細膩的文章,代碼完整,需要的朋友可以參考下
    2021-04-04
  • C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換

    C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換

    這篇文章介紹了C++使用boost::lexical_cast進行數(shù)值轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C++之Primer算術運算符詳解

    C++之Primer算術運算符詳解

    這篇文章主要介紹了C++之Primer算術運算符方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • C語言大小端模式、判斷大小端、大小端轉(zhuǎn)換方法詳解

    C語言大小端模式、判斷大小端、大小端轉(zhuǎn)換方法詳解

    這篇文章主要介紹了C語言大小端模式、判斷大小端、大小端轉(zhuǎn)換的相關資料,大端和小端是數(shù)據(jù)在內(nèi)存中的存儲方式,大端模式下高字節(jié)存于低地址,小端模式則相反,大小端問題由數(shù)據(jù)類型多字節(jié)存儲引起,不同選擇形成不同存儲模式,需要的朋友可以參考下
    2024-10-10
  • c++代碼實現(xiàn)tea加密算法的實例詳解

    c++代碼實現(xiàn)tea加密算法的實例詳解

    這篇文章主要介紹了c++代碼實現(xiàn)tea加密算法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • C語言數(shù)組的各種操作梳理

    C語言數(shù)組的各種操作梳理

    數(shù)組是一組有序的數(shù)據(jù)的集合,數(shù)組中元素類型相同,由數(shù)組名和下標唯一地確定,數(shù)組中數(shù)據(jù)不僅數(shù)據(jù)類型相同,而且在計算機內(nèi)存里連續(xù)存放,地址編號最低的存儲單元存放數(shù)組的起始元素,地址編號最高的存儲單元存放數(shù)組的最后一個元素
    2022-04-04
  • C語言實現(xiàn)數(shù)組元素排序方法詳解

    C語言實現(xiàn)數(shù)組元素排序方法詳解

    這篇文章主要為大家介紹了C語言算法練習中數(shù)組元素排序的實現(xiàn)方法,文中的示例代碼講解詳細,對我們學習C語言有一定幫助,需要的可以參考一下
    2023-02-02
  • Qt圖形圖像開發(fā)之Qt曲線圖美化QChart QScatterSeries 空心點陣圖,鼠標移動到上面顯示數(shù)值,鼠標移開數(shù)值消失效果實例

    Qt圖形圖像開發(fā)之Qt曲線圖美化QChart QScatterSeries 空心點陣圖,鼠標移動到上面顯示數(shù)值,鼠標移開

    這篇文章主要介紹了Qt圖形圖像開發(fā)之Qt曲線圖美化QChart QScatterSeries 空心點陣圖,鼠標移動到上面顯示數(shù)值,鼠標移開數(shù)值消失效果實例,需要的朋友可以參考下
    2020-03-03
  • OpenCV圖像處理之實現(xiàn)圖像膨脹腐蝕操作

    OpenCV圖像處理之實現(xiàn)圖像膨脹腐蝕操作

    圖像形態(tài)學操作是指基于形狀的一系列圖像處理操作的合集,主要是基于集合論基礎上的形態(tài)學數(shù)學對圖像進行處理。本文將為大家介紹一下如何利用OpenCV實現(xiàn)其中的腐蝕和膨脹操作,需要的可以參考一下
    2022-09-09

最新評論