1. 程式人生 > >Linux下捕捉訊號

Linux下捕捉訊號

訊號由三種處理方式:

  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訊號則執行其預設處理動作即終止程序!

相關推薦

Linux捕捉訊號

訊號由三種處理方式: 忽略 執行該訊號的預設處理動作 捕捉訊號 如果訊號的處理動作是使用者自定義函式,在訊號遞達時就呼叫這個自定義函式,這稱為捕捉訊號。 程序收到一個訊號後不會被立即處理,而是在恰當時機進行處理!即核心態返回使用者態之前 ! 但是由於訊號處理函式的程式碼在使用者空間,所

Linux訊號詳解及捕捉訊號

訊號的基本概念 每個訊號都有一個編號和一個巨集定義名稱 ,這些巨集定義可以在 signal.h 中找到。 使用kill -l命令檢視系統中定義的訊號列表: 1-31是普通訊號 regular signal(非可靠訊號); 34-64是實時訊號 real time sign

Linux訊號(三)----捕捉訊號與sleep模擬

Linux下的訊號(一):訊號的基本概念與產生 Linux下的訊號(二):阻塞訊號 一,什麼是捕捉訊號? 1,捕捉訊號:訊號處理方式三種方式中的一種,意思是既不忽略該訊號,又不執行訊號預設的動作,而是讓訊號執行自定義動作。捕捉訊號要使用signal函式

linux訊號機制(signel)--持續更新中

1、訊號的基本概念        程序之間可以互相通過系統呼叫kill傳送軟中斷訊號。核心也可以因為內部事件而給程序傳送訊號,通知程序發生了某個事件。程序通過系統呼叫signal來指定程序對某個訊號的處理行為。2、訊號本質是int型數字編號(事先定義好的)        解釋

Linux訊號量看執行緒排程時間

前幾天寫了一篇文章關於Linux下程序排程時間的,本意是想測試下實時效能的,包括中斷響應時間等等,這個可能需要藉助於硬體發出終端來測試, 那片文章是講的是通過傳送訊號給另一個程序,然後測量傳送訊號到進入訊號處理程式之間的時間 訊號只是針對程序來說的,今天

linux signal訊號機制的透徹分析與各種例項講解

首先感謝上述兩位博主的詳細講解。 雖然內容有點長,但是分析的很全面,各種例項應用基本都考慮到了。 本文將從以下幾個方面來闡述訊號: (1)訊號的基本知識 (2)訊號生命週期與處理過程分析 (3) 基本的訊號處理函式 (4) 保護臨界區不被中斷 (5)

LinuxSignal訊號系統呼叫

前面兩節已經介紹了有關訊號的大部分知 識。這一節我們來了解一下這些系統呼叫。其中,系統呼叫signal是程序用來設定某個訊號的處理方法,系統呼叫kill是用來發送訊號給指定程序的。這 兩個呼叫可以形成訊號的基本操作。後兩個呼叫pause和alarm是通過訊號實現的程序暫停和

Linux訊號(一)----訊號的基本概念與產生

一,訊號的基本概念 1,什麼是訊號? 日常生活中,當我們走到馬路上時,看到的綠燈是一種訊號,它能提示我們怎樣安全的過馬路。又比如,新學期開始學校給每個班發的課表也是一種訊號,它能提示同學們在適當的時間地點去上相應的課程而不是虛度光陰……生活中其

Linux訊號(signal)

一、訊號的概念: 要理解訊號,我們先來進入一個場景。使用者在shell下開啟一個前臺程序,正在執行。在鍵盤上按下ctrl+C的組合鍵,當前前臺程序會中斷。是因為鍵盤上輸入的訊號通過硬體傳輸給驅動程式,將ctrl+C轉化為SIGNAL傳給該程序的PCB,修改了P

Linux忽略訊號SIGPIPE的方法

最近為測試自己寫的伺服器,臨時寫了一個客戶端,總是發現客戶端收到SIGPIPE的訊號,然後程序退出。 為了客戶端程序收到SIGPIPE不退出,我打算忽略該訊號,下面是我用過的方法: (1)間接忽略

linux訊號LinuxSignal訊號太詳細了,終於找到了

訊號是Linux程式設計中非常重要的部分,本文將詳細介紹訊號機制的基本概念、Linux對訊號機制的大致實現方法、如何使用訊號,以及有關訊號的幾個系統呼叫。  訊號機制是程序之間相互傳遞訊息的一種方法,訊號全稱為軟中斷訊號,也有人稱作軟中斷。從它的命名可以看出,它的實質和使用很象中斷。所以,訊號可以說是程序控

linux訊號量操作示例

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <pthread.h>#include <errno.h>#include

解決Linux網路程式設計(sendto send )出現 SIGPIPE 訊號導致程式異常終止的問題

引言 最近在Linux下網路程式設計時,出現SIGPIPE 訊號導致程式異常終止,本文記錄下解決的方法以及相應的知識。 SIGPIPE 訊號資料 什麼時候出現此訊號,APUE中有關此訊號的解釋如下: Linux man手冊有關此訊號的解釋: man 7 signal SI

Linux的程序訊號處理過程

訊號的產生 訊號的產生方式 鍵盤產生 鍵盤產生的訊號只能傳送給前臺程序。例如:[Ctrl+C]… 程式異常 除0錯誤。除0錯誤會導致硬體錯誤。 core dumped(核心轉儲):當程序異常退出時,作

linux訊號量及其SEM_UNDO標誌

AT&T的貝爾實驗室,對Unix早期的程序間通訊進行了改進和擴充,形成了"system V IPC",其通訊程序主要侷限在單個計算機內。IPC物件指的是共享記憶體(share memory)、訊息佇列(message queue)和訊號燈集(semaphore)。 訊號燈(sema

linux的C語言開發(訊號處理)

                【 宣告:版權所有,歡迎轉載,請勿用於商業用途。  聯絡信箱:feixiaoxing @163.com】    訊號處理是linux程式的一個特色。用訊號處理來模擬作業系統的中斷功能,對於我們這些系統程式設計師來說是最好的一個選擇了。要想使用訊號處理功能,你要做的就是填寫一個訊

linuxc程式設計之訊號量semget,semop,semctl函式

訊號量 今天去參加北京市的植樹志願者活動啦!早上起來的挺早的,6:10就被傑子給叫起來啦,帶著對春天的嚮往,我們坐著不花錢的大巴去做為市領導服務去啦!發了一個小紅帽還有一個紅色的制服。 唉。。。說好

linux python 監控usb裝置訊號

1. linux下訊息記錄   關於系統的各種訊息一般都會記錄在/var/log/messages檔案中,有些主機在中預設情況下有可能沒有啟用,具體配置方法可參考下面這篇部落格:   系統日誌配置 /var/log/messages 2. python

Linux五種I/O模型詳解(阻塞IO、非阻塞IO、IO複用、訊號驅動、非同步IO)

文章轉載自微信公眾號:漫話程式設計 1 什麼是I/O 程式是由資料+指令構成的,執行程式的過程可以分成下面這幾步: 1.將程式碼載入到記憶體中,逐條執行記憶體中的程式碼 2.在執行程式碼的過程中,可能需要對檔案的讀寫,即將檔案輸入(Input)

linuxqt5.7訊號與槽之文字框同步

#include "signal.h" #include "ui_signal.h" signal::signal(QWidget *parent) :     QMainWindow(parent),     ui(new Ui::signal)//建立 {     ui->setupUi(this)