Linux下捕捉訊號
訊號由三種處理方式:
- 忽略
- 執行該訊號的預設處理動作
- 捕捉訊號
如果訊號的處理動作是使用者自定義函式,在訊號遞達時就呼叫這個自定義函式,這稱為捕捉訊號。
程序收到一個訊號後不會被立即處理,而是在恰當時機進行處理!即核心態返回使用者態之前 !
但是由於訊號處理函式的程式碼在使用者空間,所以這增加了核心處理訊號捕捉的複雜度。
核心實現訊號捕捉的步驟:
- 使用者為某訊號註冊一個訊號處理函式sighandler。
- 當前正在執行主程式,這時候因為中斷、異常或系統呼叫進入核心態。
- 在處理完異常要返回使用者態的主程式之前,檢查到有訊號未處理,並發現該訊號需要按照使用者自定義的函式來處理。
- 核心決定返回使用者態執行sighandler函式,而不是恢復main函式的上下文繼續執行!(sighandler和main函式使用的是不同的堆疊空間,它們之間不存在呼叫和被呼叫的關係,是兩個獨立的控制流程)
- sighandler函式返回後,執行特殊的系統呼叫sigreturn從使用者態回到核心態
- 檢查是否還有其它訊號需要遞達,如果沒有 則返回使用者態並恢復主程式的上下文資訊繼續執行。
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是指定訊號的編號。
處理方式:
- 若act指標非空,則根據act結構體中的訊號處理函式來修改該訊號的處理動作。
- 若oact指標非 空,則通過oact傳出該訊號原來的處理動作。
- 現將原來的處理動作備份到oact裡,然後根據act修改該訊號的處理動作。
(注:後兩個引數都是輸入輸出型引數!)
將sa_handler三種可選方式:
- 賦值為常數SIG_IGN傳給sigaction表示忽略訊號;
- 賦值為常數SIG_DFL表示執行系統預設動作;
- 賦值為一個函式指標表示用自定義函式捕捉訊號,或者說向核心註冊一個訊號處理函 數,該函式返回值為void,可以帶一個int引數,通過引數可以得知當前訊號的編號,這樣就可以用同一個函式處理多種訊號。
(注:這是一個回撥函式,不是被main函式呼叫,而是被系統所呼叫)
當某個訊號的處理函式被呼叫時,核心自動將當前訊號加入程序的訊號遮蔽字,當訊號處理函式返回時自動恢復原來的訊號遮蔽字,這樣就保證了在處理某個訊號時,如果這種訊號再次產生,那麼 它會被阻塞到當前處理結束為止。
pause
pause函式使呼叫程序掛起直到有訊號遞達!
#include <unistd.h> int pause(void);
處理方式:
- 如果訊號的處理動作是終止程序,則程序終止,pause函式沒有機會返回;
- 如果訊號的處理動作是忽略,則程序繼續處於掛起狀態,pause不返回;
- 如果訊號的處理動作是捕捉,則呼叫了訊號處理函式之後pause返回-1,errno設定為EINTR。
所以pause只有出錯的返回值(類似exec函式家族)。錯誤碼EINTR表示“被訊號中斷”。
舉個栗子
- 定義一個鬧鐘,約定times秒後,核心向該程序傳送一個SIGALRM訊號;
- 呼叫pause函式將程序掛起,核心切換到別的程序執行;
- times秒後,核心向該程序傳送SIGALRM訊號,發現其處理動作是一個自定義函式,於是切回用戶態執行該自定義處理函式;
-
進入sig_alrm函式時SIGALRM訊號被自動遮蔽,從sig_alrm函式返回時SIGALRM訊號自動解除遮蔽。然後自動執行特殊的系統呼叫sigreturn再次進入核心,之後再返回使用者態繼續執行程序的主控制流程(main函式呼叫的mytest函式)。
-
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)
Linux下Signal訊號系統呼叫
前面兩節已經介紹了有關訊號的大部分知 識。這一節我們來了解一下這些系統呼叫。其中,系統呼叫signal是程序用來設定某個訊號的處理方法,系統呼叫kill是用來發送訊號給指定程序的。這 兩個呼叫可以形成訊號的基本操作。後兩個呼叫pause和alarm是通過訊號實現的程序暫停和
Linux下的訊號(一)----訊號的基本概念與產生
一,訊號的基本概念 1,什麼是訊號? 日常生活中,當我們走到馬路上時,看到的綠燈是一種訊號,它能提示我們怎樣安全的過馬路。又比如,新學期開始學校給每個班發的課表也是一種訊號,它能提示同學們在適當的時間地點去上相應的課程而不是虛度光陰……生活中其
Linux下的訊號(signal)
一、訊號的概念: 要理解訊號,我們先來進入一個場景。使用者在shell下開啟一個前臺程序,正在執行。在鍵盤上按下ctrl+C的組合鍵,當前前臺程序會中斷。是因為鍵盤上輸入的訊號通過硬體傳輸給驅動程式,將ctrl+C轉化為SIGNAL傳給該程序的PCB,修改了P
Linux下忽略訊號SIGPIPE的方法
最近為測試自己寫的伺服器,臨時寫了一個客戶端,總是發現客戶端收到SIGPIPE的訊號,然後程序退出。 為了客戶端程序收到SIGPIPE不退出,我打算忽略該訊號,下面是我用過的方法: (1)間接忽略
linux訊號Linux下Signal訊號太詳細了,終於找到了
訊號是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程式的一個特色。用訊號處理來模擬作業系統的中斷功能,對於我們這些系統程式設計師來說是最好的一個選擇了。要想使用訊號處理功能,你要做的就是填寫一個訊
linux下c程式設計之訊號量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)
linux下qt5.7訊號與槽之文字框同步
#include "signal.h" #include "ui_signal.h" signal::signal(QWidget *parent) : QMainWindow(parent), ui(new Ui::signal)//建立 { ui->setupUi(this)