在linux的程序中可以接收到各種的訊號,並且如果你不對訊號進行處理,linux中的程序就會採用預設的處理方式處理,比如ctrl-c的訊號,程序對它的處理就是終止程序的執行。
在linux中,我們也可以在程序中遮蔽掉某些訊號,使程序不去處理這些訊號,但其中的sigkill和sigstop是不能被阻塞的。
在這裡先介紹幾個訊號的函式:
int sigempty(sigset_t *set); // 清空訊號集set
int sigfillset(sigset_t *set); // 填滿訊號集,即讓set包含所有的訊號
int sigaddset(sigset_t *set, int signo); // 在set中增加signo訊號
int sigdelset(sigset_t *set, int signo); // 在set中去掉signo訊號
int sigismember(sigset_t *set, int signo); // 訊號signo是否在訊號集set中
int sigprocmask(int how, const sigset_t set, sigset_t oset); // 若oset非空,則程序的當前訊號遮蔽字通過oset返回,若set是乙個非空指標,著引數how指示如何修改當前訊號的遮蔽字,how可以取三個值:
sig_block:增加乙個訊號。
sig_unblock:解除乙個訊號。
sig_setmask:該程序的訊號將被set訊號集取代。
int sigpengding(sigset_t *set); // 該函式返回訊號集,該訊號通過set引數返回。
以上函式都在#include 標頭檔案中。
下面用《unix環境高階程式設計》裡的乙個例子說明一下,**有所修改,先看**(main.c,裡面有個人對**的注釋):
view plaincopy to clipboardprint?
#include
#include
#include
static void sig_quit(int);
int
main(void)
//設定乙個空的訊號集
sigemptyset(&newmask);
sigaddset(&newmask, sigquit); // 在這個訊號集中增加sigquit訊號
//在當前程序中增加newmask訊號集作為遮蔽訊號集,oldmask返回當前程序的訊號集
if (sigprocmask(sig_block, &newmask, &oldmask) < 0)
sleep(5);
//返回當前程序訊號集
if (sigpending(&pendingmask) < 0)
//檢查sigquit訊號是否在當前訊號集中
if (sigismember(&pendingmask, sigquit))
printf("/nsigquit pending/n");
//恢復程序的訊號集
if (sigprocmask(sig_setmask, &oldmask, null) < 0)
printf("sigquit unblocked/n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
} #include
#include
#include
static void sig_quit(int);
int
main(void)
//設定乙個空的訊號集
sigemptyset(&newmask);
sigaddset(&newmask, sigquit); // 在這個訊號集中增加sigquit訊號
//在當前程序中增加newmask訊號集作為遮蔽訊號集,oldmask返回當前程序的訊號集
if (sigprocmask(sig_block, &newmask, &oldmask) < 0)
sleep(5);
//返回當前程序訊號集
if (sigpending(&pendingmask) < 0)
//檢查sigquit訊號是否在當前訊號集中
if (sigismember(&pendingmask, sigquit))
printf("/nsigquit pending/n");
//恢復程序的訊號集
if (sigprocmask(sig_setmask, &oldmask, null) < 0)
printf("sigquit unblocked/n");
sleep(5);
exit(0);
}static void sig_quit(int signo)
} 編譯: gcc main.c
生成:a.out
執行:./a.out
輸出如下(ubuntu9.10):
^/
sigquit pending
caught sigquit
sigquit unblocked
^/退出
下面解釋一下輸出:
^/ 在第一次sleep(5)的5秒中內產生訊號一次(按ctrl+/)
sigquit pending 從sleep返回後
caught sigquit 在訊號處理函式中
sigquit unblocked 從sigprocmask返回後
^/退出 再次產生訊號
我們對著程式來看下輸出。
在我們設定sigquit遮蔽字和恢復程序的訊號集這段時間,我們產生的sigquit訊號,我們的程序並沒去處理,所以輸出了sigquit pending 。
在我們恢復程序的訊號集後,我們程序就撲捉到了我們剛才產生的訊號,因而就輸出了caught sigquit,在sig_quit函式中,我們恢復了sigquit的預設處理方式(即終止程序執行),程序當我們再次產生sigquit訊號,程序就退出了。
當我們產生程序時,一些unix系統會對程序中要處理的訊號進行排隊,我們的程序會對訊號佇列中的訊號進行處理。我們再執行一下剛才的程式,在第一次sleep(5)的5秒中內產生訊號10次訊號,看下會怎麼樣,下面是我的輸出:
^/^/^/^/^/^/^/^/^/^/
sigquit pending
caught sigquit
sigquit unblocked
^/退出
下面解釋一下輸出:
^/^/^/^/^/^/^/^/^/^/ 在第一次sleep(5)的5秒中內產生訊號10次訊號
sigquit pending 從sleep返回後
caught sigquit 從sigprocmask返回後
sigquit unblocked 從sigprocmask返回後
^/退出 再次產生訊號
這裡可以看到linux系統對沒有對訊號進行排隊,產生10次訊號,只處理一次。
在上面的例子中,我們用signal函式來指定訊號的處理函式,用sigprocmask來指定訊號遮蔽字,其實這些都可以在乙個函式中解決,它就是sigaction ,推薦使用sigaction函式。
pthread_sigmask與sigprocmask。前者是執行緒安全的。
pthread_sigmask改變的是執行緒的訊號集與整個程序無關。
Linux中如何遮蔽訊號
本篇文章主要學習linux的訊號處理機制,著重學習遮蔽訊號部分。遮蔽訊號處理的兩種方式類似於訊號的捕獲,一種方式是直接對其設定,另一種方式是先獲得描述符的掩碼,然後對其設定操作。本文主要參考自 嵌入式linux系統使用開發 作者何永琪,thanks.在linux系統中,如何處理某個程序傳送的乙個特定...
linux 訊號遮蔽
include include include include include include sigemptyset newmask 獲取空遮蔽訊號集 sigfillset newmask 獲取遮蔽了所有訊號的遮蔽訊號集,除了那兩個sigkill sigstop sigpending pendma...
Linux中的程序訊號
訊號概念訊號 系統為了響應某些狀況而產生的事件,程序收到訊號需要採取相應的動作。訊號產生訊號產生的條件 1 按下終端鍵 ctrl c ctrl 2 硬體異常 除零操作 無效記憶體 3 某些軟條件發生 時間片到 4 管道破裂 用kill l 可以檢視系統定義的訊號列表 訊號產生的方式 1 通過終端鍵產...