Linux下捕捉信號

来源:http://www.cnblogs.com/Lynn-Zhang/archive/2016/08/15/5772403.html
-Advertisement-
Play Games

關於 信號signal的知識鋪墊 點這裡 信號由三種處理方式: 如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個自定義函數,這稱為捕捉信號。 進程收到一個信號後不會被立即處理,而是在恰當時機進行處理!即內核態返回用戶態之前 ! 但是由於信號處理函數的代碼在用戶空間,所以這增加了內核處理信號 ...


關於 信號signal的知識鋪墊 點這裡

信號由三種處理方式:

  1. 忽略
  2. 執行該信號的預設處理動作
  3. 捕捉信號

如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個自定義函數,這稱為捕捉信號

進程收到一個信號後不會被立即處理,而是在恰當時機進行處理!即內核態返回用戶態之前 !

但是由於信號處理函數的代碼在用戶空間,所以這增加了內核處理信號捕捉的複雜度。

內核實現信號捕捉的步驟:

  1. 用戶為某信號註冊一個信號處理函數sighandler。
  2. 當前正在執行主程式,這時候因為中斷、異常或系統調用進入內核態。
  3. 在處理完異常要返回用戶態的主程式之前,檢查到有信號未處理,併發現該信號需要按照用戶自定義的函數來處理。
  4. 內核決定返回用戶態執行sighandler函數,而不是恢復main函數的上下文繼續執行!(sighandler和main函數使用的是不同的堆棧空間,它們之間不存在調用和被調用的關係,是兩個獨立的控制流程)
  5. sighandler函數返回後,執行特殊的系統調用sigreturn從用戶態回到內核態
  6. 檢查是否還有其它信號需要遞達,如果沒有 則返回用戶態並恢復主程式的上下文信息繼續執行。

 

signal

給某一個進程的某一個信號(標號為signum)註冊一個相應的處理函數,即對該信號的預設處理動作進行修改,修改為handler函數指向的方式;

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

signal函數接受兩個參數:一個整型的信號編號,以及一個指向用戶定義的信號處理函數的指針。  

此外,signal函數的返回值是一個指向調用用戶定義信號處理函數的指針。

sigaction

sigaction函數可以讀取和修改與指定信號相關聯的處理動作。

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction
{
               void     (*sa_handler)(int);          //信號處理方式
               void     (*sa_sigaction)(int, siginfo_t *, void *);  //實時信號的處理方式  暫不討論
               sigset_t   sa_mask;   //額外屏蔽的信號
               int        sa_flags;
               void     (*sa_restorer)(void);     
};

signum是指定信號的編號。

處理方式:

  1. 若act指針非空,則根據act結構體中的信號處理函數來修改該信號的處理動作。
  2. 若oact指針非 空,則通過oact傳出該信號原來的處理動作。
  3. 現將原來的處理動作備份到oact里,然後根據act修改該信號的處理動作。

(註:後兩個參數都是輸入輸出型參數!)

將sa_handler三種可選方式:

  1. 賦值為常數SIG_IGN傳給sigaction表示忽略信號;
  2. 賦值為常數SIG_DFL表示執行系統預設動作;
  3. 賦值為一個函數指針表示用自定義函數捕捉信號,或者說向內核註冊一個信號處理函 數,該函數返回值為void,可以帶一個int參數,通過參數可以得知當前信號的編號,這樣就可以用同一個函數處理多種信號。

(註:這是一個回調函數,不是被main函數調用,而是被系統所調用)

  當某個信號的處理函數被調用時,內核自動將當前信號加入進程的信號屏蔽字,當信號處理函數返回時自動恢複原來的信號屏蔽字,這樣就保證了在處理某個信號時,如果這種信號再次產生,那麼 它會被阻塞到當前處理結束為止。

 pause

pause函數使調用進程掛起直到有信號遞達!

#include <unistd.h>
int pause(void);

處理方式: 

  • 如果信號的處理動作是終止進程,則進程終止,pause函數沒有機會返回;
  • 如果信號的處理動作是忽略,則進程繼續處於掛起狀態,pause不返回;
  • 如果信號的處理動作是捕捉,則調用了信號處理函數之後pause返回-1,errno設置為EINTR。

所以pause只有出錯的返回值(類似exec函數家族)。錯誤碼EINTR表示“被信號中斷”。

 舉個慄子

  1. 定義一個鬧鐘,約定times秒後,內核向該進程發送一個SIGALRM信號;
  2. 調用pause函數將進程掛起,內核切換到別的進程運行;
  3. times秒後,內核向該進程發送SIGALRM信號,發現其處理動作是一個自定義函數,於是切回用戶態執行該自定義處理函數;
  4. 進入sig_alrm函數時SIGALRM信號被自動屏蔽,從sig_alrm函數返回時SIGALRM信號自動解除屏蔽。然後自動執行特殊的系統調用sigreturn再次進入內核,之後再返回用戶態繼續執行進程的主控制流程(main函數調用的mytest函數)。

  5. pause函數返回-1,然後調用alarm(0)取消鬧鐘,調用sigaction恢復SIGALRM信號以前的處理 動作。

/*************************************************************************
 > File Name: Pause.c
 > Author:Lynn-Zhang 
 > Mail: [email protected]
 > Created Time: Sun 14 Aug 2016 12:27:03 PM CST
 ************************************************************************/

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_alarm(int signum)
{
    printf("I am a custom handler!\n");
}
void mysleep(unsigned int times)
{
    //註冊兩個信號處理動作
    struct sigaction new,old;
    new.sa_handler=sig_alarm; //信號處理函數
    sigemptyset(&new.sa_mask);//不屏蔽任何信號屏蔽字
    new.sa_flags=0;
    
    //對SIGALRM 信號的預設處理動作修改為自定義處理動作
    sigaction(SIGALRM,&new,&old);
    alarm(times);
    pause(); //掛起等待
    alarm(1); 
    sleep(2);
    alarm(0); //取消鬧鐘 
    //恢復SIGALRM 信號到預設處理動作
    sigaction(SIGALRM,&old,NULL);
    alarm(1);
    sleep(2);
}
int main()
{
    while(1)
    {
        mysleep(2);
        printf("many seconds passed\n");
        printf("###################\n");
    }
    return 0;
}

    

定義一個鬧鐘並掛起等待,收到信號後執行自定義處理動作,在沒有恢復預設處理動作前,收到SIGALRM信號都會按照其自定義處理函數來處理。恢復自定義處理動作之後收到SIGALRM信號則執行其預設處理動作即終止進程!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、線程標識 和每個進程都有一個進程ID一樣,每個線程也有一個線程ID,線程ID是以pthread_t數據類型來表示的,在Linux中,用無符號長整型表示pthread_t,Solaris 把phread_t數據類型表示為無符號整型,FreeBSD 和Mac OS X 用一個指向pthread結構的 ...
  • 安裝VirtualBox為了共用文件夾,折騰了一晚上!網上的很多資料都不是很全面,這裡就全面的總結一下,如果有其他的疑問,可以留言多多交流。 "VirtualBox下載地址,版本為5.1.2" 設置共用文件路徑 點擊虛擬機 設置 選擇 共用文件夾 (圖1 設置共用文件夾) 設置共用文件夾路徑 1 選 ...
  • Linux作為操作系統,Apache作為Web伺服器,MySQL作為資料庫,PHP作為伺服器端腳本解釋器。由於這四個軟體都是免費或開放式源碼軟體,因此使用這種不用花一分錢(人工成本除外)就可以建立起一個穩定、免費的網站系統,被業界稱為“LAMP”組合。今天,我們就講講MySQL資料庫的安裝和簡單應用 ...
  • CoreOS Hyper-V 安裝, Install to disck 準備 安裝鏡像 https://coreos.com/releases/ 選擇版本, 點 Browse Images, 下載以下文件 (本文以 Alpha 為例) coreos_production_iso_image.iso ...
  • 輸入輸出重定向是在 linux shell 中經常使用的一個功能,本編博文簡單介紹了什麼是輸入輸出以及操作方法 ...
  • 這是之前在Linux下配置Node環境變數時踩過的坑,今天又有小伙伴質詢這個問題,因此記錄下來,不僅是給新童鞋們一些參考,也方便日後查閱 在這之前,相信都已經安裝好了,沒安裝的可以查看博主另一篇文章 http://www.cnblogs.com/Halifa/p/5772263.html 配置Nod ...
  • RVA是相對虛擬地址(Relative Virtual Address)的縮寫。RVA是當PE 文件被裝載到記憶體中後,某個數據位置相對於文件頭的偏移量。 例如:導入表的位置和大小可以從PE文件頭中IMAGE_OPTIONAL_HEADER32結構的數據目錄欄位中獲取,對應的項目是DataDirect... ...
  • RancherOS Hyper-V 安裝, Install to disk 打開 Hyper-V 管理界器, 新建虛擬機 輸入名稱和存儲位置 選擇一代 最低 1024M 配置網路 創建虛擬磁碟 設置啟動 ISO, 下載 創建完成 設置處理器 設置記憶體, 註: 如果使用動態記憶體, 需限定下最大記憶體 啟 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...