<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    利用linux信號機制調試段錯誤(Segment fault)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    在實際開發過程中,大家可能會遇到段錯誤的問題,雖然是個老問題,但是其帶來的隱患是極大的,只要出現一次,程序立即崩潰中止。如果程序運行在PC中,segment fault的調試相對比較方便,因為可以通過串口、顯示器可以查看消息,只要程序運行,通過GDB調試工具即可捕捉產生segment fault的具體原因。但是不知大家有沒有想法,當程序運行在嵌入式設備上時,你所面臨資源的缺乏,你沒有串口打印信息,沒有顯示器可查看,你不知道程序運行的狀態,如果程序的產生segment falut這種bug發生的周期1年之內只發生過三四次,時間又不確定,你又如何調試知道程序發生錯誤的具體位置呢?等等問題實在令人糾結。

            解決此問題的方式方法有如下幾種:

           1 在產品發布之前,盡量將所有segment fault產生原因找出,全部消除(最理想情況下)

           2 在程序中的關鍵位置增加打印信息,設定打印級別,通過打信的信息縮小查bug的范圍,如果是嵌入式設備,需要將這些信息寫入文件,保存在flash中。

           3 利用看門狗喂狗,如果程序中止或長期陷入死循環,將重新加載程序

           4 利用linux信號機制來解決段錯誤問題(有點類似于軟看門狗)

     

     

           下面我著重講解第4要點的解決方式:

            首先,我先敘述下我的總體思路,假設我的程序在某處調用一函數dummy_func(),這個函數有個segment fault段錯誤,如果你程序沒對其進行處理,不用懷疑,你的程序馬上掛掉,如果是嵌入式設備里的程序,你可能不知道產生segment fault的具體原因和具體位置,只能看log日志慢慢分析。我們知道,在linux的信號機制中,當產生segment fault錯誤時,程序會產生SIGSEGV信號,于是我們試想,如果我們在程序中能夠及時捕捉到此信號,然后在此信號處理函數中重新加載此應用程序,就可以實現類似看門狗的功能,暫且將這種方法稱之為軟件看門狗吧。但是此方法只是權宜之計,它可以讓你的產品在客戶面前保持良好印象(因為如果程序掛掉后又重新加載了,而客戶不知道),而不至于長期很頻繁的去現場解決此問題,這種方式適用于產生段錯誤的周期具有不確定性,其實我們都知道遇到segment fault我們還得解決此問題產生的具體原因,這才是正確的解決方式。

            下面我列出完整的程序源碼,雖然簡單,但是非常有用:

     

    /******************************程序開始 **********************************/

     

    #include <stdio.h>
    #include <signal.h>
    #include <string.h>
    #include <stdlib.h>

    char main_status = 0;

    /***********************
     * 此函數產生一個段錯誤
     * *********************/
    void dummy_func(void)
    {
        printf("hello world/n");
        char *p = NULL;     //0地址
        *p = 0x1a;             //對0地址寫入數據,出現段錯誤
        return;
    }



    /************************
     * 此函數用于重新加載程序
     ************************/
    void deal(void)
    {
       char buffer[255];
       memset(buffer, 0, sizeof(buffer));
       sprintf(buffer, "cd ~/test");
       system(buffer);

       /*
        *此延時很重要,如果不加延時,ctrl+c的信號無法及時處理(即ctrl+c失效),程序將循環加載    
        * 如果不加延時,程序又重新執行后面./test1語句將重新加載應用程序了
         */
         sleep(5);  

       memset(buffer, 0, sizeof(buffer));
       sprintf(buffer, "./test1");
       system(buffer);
       printf ("xxxxxxxxxxxxxxx/n");
        
       if( 1 == main_status )
            exit(0);
    }


    /**************************
     * 捕捉到ctrl+c信號的處理函數
     **************************/
    void ctrl_c_func(int signo)
    {
        printf("stop the demo/n");
        main_status = 1;  //置標志位
        exit(0);
    }


    int ctrl_c_func_init(void)
    {
        int ret = 0;
        struct sigaction act;

        act.sa_handler = ctrl_c_func;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;

        ret = sigaction(SIGINT, &act, NULL);
    }



    /****************************
     * main主程序
     ****************************/
    int main(int argc, char **argv)
    {
        signal(SIGSEGV, &deal);   //捕捉SIGSEGV信號
        signal(SIGINT, &ctrl_c_func);  //捕捉SIGINT信號
    //    ctrl_c_func_init();  //如果不用上面捕捉,調用這個函數也行

        while(1)
        {
            if( 1 == main_status )  //如果接收到標志位,則退出
            { 
                 exit(0);
            }
            dummy_func();  //調用產生segment fault函數
        }
        return 0;
    }
    /******************************程序結束 **********************************/

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全