Linux信號、信號處理和信號處理函數

相關的更詳細解釋:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html

信號(signal)是一種軟件中斷,它提供了一種處理異步事件的方法,也是進程間惟一的異步通信方式。在Linux系統中,根據POSIX標準擴展以後的信號機制,不僅可以用來通知某種程序發生了什麼事件,還可以給進程傳遞數據。

一、信號的來源

信號的來源可以有很多種試,按照產生條件的不同可以分爲硬件和軟件兩種。

1、  硬件方式

當用戶在終端上按下某鍵時,將產生信號。如按下<Ctral + C>組合鍵後將產生一個SIGINT信號。

硬件異常產生信號:除數據、無效的存儲訪問等。這些事件通常由硬件(:CPU)檢測到,並將其通知給Linux操作系統內核,然後內核生成相應的信號,並把信號發送給該事件發生時正在進行的程序。

2、  軟件方式

用戶在終端下調用kill命令向進程發送任務信號。

進程調用killsigqueue函數發送信號。

當檢測到某種軟件條件已經具備時發出信號,如由alarmsettimer設置的定時器超時時將生成SIGALRM信號。

二、信號的種類

Shell下輸入kill –l 可顯示Linux 系統支持的全部依賴,信號列表如下:

1) SIGHUP         2) SIGINT            3) SIGQUIT        4) SIGILL
5) SIGTRAP        6) SIGABRT          7) SIGBUS         8) SIGFPE
9) SIGKILL        10) SIGUSR1         11) SIGSEGV       12) SIGUSR2
13) SIGPIPE       14) SIGALRM         15) SIGTERM       16) SIGSTKFLT
17) SIGCHLD       18) SIGCONT         19) SIGSTOP       20) SIGTSTP
21) SIGTTIN       22) SIGTTOU         23) SIGURG        24) SIGXCPU
25) SIGXFSZ       26) SIGVTALRM       27) SIGPROF       28) SIGWINCH
29) SIGIO         30) SIGPWR          31) SIGSYS        34) SIGRTMIN
35) SIGRTMIN+1     36) SIGRTMIN+2      37) SIGRTMIN+3    38) SIGRTMIN+4
39) SIGRTMIN+5     40) SIGRTMIN+6      41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9     44) SIGRTMIN+10     45) SIGRTMIN+11   46) SIGRTMIN+12
47) SIGRTMIN+13    48) SIGRTMIN+14     49) SIGRTMIN+15   50) SIGRTMAX-14
51) SIGRTMAX-13    52) SIGRTMAX-12     53) SIGRTMAX-11   54) SIGRTMAX-10
55) SIGRTMAX-9     56) SIGRTMAX-8      57) SIGRTMAX-7    58) SIGRTMAX-6
59) SIGRTMAX-5     60) SIGRTMAX-4      61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1     64) SIGRTMAX   

信號的值定義在signal.h中,在Linux中沒有1632這兩個信號。上面信號的含義如下:

(1) SIGHUP:當用戶退出Shell時,由該Shell啓的發所有進程都退接收到這個信號,默認動作爲終止進程。

(2) SIGINT:用戶按下<Ctrl + C>組合鍵時,用戶端時向正在運行中的由該終端啓動的程序發出此信號。默認動作爲終止進程。

(3) SIGQUIT:當用戶按下<Ctrl + />組合鍵時產生該信號,用戶終端向正在運行中的由該終端啓動的程序發出此信號。默認動作爲終止進程併產生core文件。

(4) SIGILL CPU檢測到某進程執行了非法指令。默認動作爲終止進程併產生core文件。

(5) SIGTRAP:該信號由斷點指令或其他trap指令產生。默認動作爲終止進程併產生core文件。

(6) SIGABRT:調用abort函數時產生該信號。默認動作爲終止進程併產生core文件。

(7) SIGBUS:非法訪問內存地址,包括內存地址對齊(alignment)出錯,默認動作爲終止進程併產生core文件。

(8) SIGFPE:在發生致命的算術錯誤時產生。不僅包括浮點運行錯誤,還包括溢出及除數爲0等所有的算術錯誤。默認動作爲終止進程併產生core文件。

(9) SIGKILL:無條件終止進程。本信號不能被忽略、處理和阻塞。默認動作爲終止進程。它向系統管理員提供了一種可以殺死任何進程的方法。

(10) SIGUSR1:用戶定義的信號,即程序可以在程序中定義並使用該信號。默認動作爲終止進程。

(11) SIGSEGV:指示進程進行了無效的內存訪問。默認動作爲終止進程並使用該信號。默認動作爲終止進程。

(12) SIGUSR2:這是另外一個用戶定義信號,程序員可以在程序中定義並使用該信號。默認動作爲終止進程。

(13) SIGPIPEBroken pipe:向一個沒有讀端的管道寫數據。默認動作爲終止進程。

(14) SIGALRM:定時器超時,超時的時間由系統調用alarm設置。默認動作爲終止進程。

(15) SIGTERM:程序結束(terminate)信號,與SIGKILL不同的是,該信號可以被阻塞和處理。通常用來要求程序正常退出。執行Shell命令kill時,缺少產生這個信號。默認動作爲終止進程。

(16) SIGCHLD:子程序結束時,父進程會收到這個信號。默認動作爲忽略該信號。

(17) SIGCONT:讓一個暫停的進程繼續執行。

(18) SIGSTOP:停止(stopped)進程的執行。注意它和SIGTERM以及SIGINT的區別:該進程還未結束,只是暫停執行。本信號不能被忽略、處理和阻塞。默認作爲暫停進程。

(19) SIGTSTP:停止進程的動作,但該信號可以被處理和忽略。按下<Ctrl + Z>組合鍵時發出該信號。默認動作爲暫停進程。

(20) SIGTTIN:當後臺進程要從用戶終端讀數據時,該終端中的所有進程會收到SIGTTIN信號。默認動作爲暫停進程。

(21) SIGTTOU:該信號類似於SIGTIN,在後臺進程要向終端輸出數據時產生。默認動作爲暫停進程。

(22) SIGURG:套接字(socket)上有緊急數據時,向當前正在運行的進程發出此信號,報告有緊急數據到達。默認動作爲忽略該信號。

(23) SIGXCPU:進程執行時間超過了分配給該進程的CPU時間,系統產生該信號併發送給該進程。默認動作爲終止進程。

(24) SIGXFSZ:超過文件最大長度的限制。默認動作爲yl終止進程併產生core文件。

(25) SIGVTALRM:虛擬時鐘超時時產生該信號。類似於SIGALRM,但是它只計算該進程佔有用的CPU時間。默認動作爲終止進程。

(26) SIGPROF:類似於SIGVTALRM,它不僅包括該進程佔用的CPU時間還抱括執行系統調用的時間。默認動作爲終止進程。

(27) SIGWINCH:窗口大小改變時發出。默認動作爲忽略該信號。

(28) SIGIO:此信號向進程指示發出一個異步IO事件。默認動作爲忽略。

(29) SIGPWR:關機。默認動作爲終止進程。

(30) SIGRTMIN~SIGRTMAXLinux的實時信號,它沒有固定的含義(或者說可以由用戶自由使用)。注意,Linux線程機制使用了前3個實時信號。所有的實時信號的默認動作都是終止進程。

1、可靠信號與不可靠信號

Linux系統中,信號的可靠性是指信號是否會丟失,或者說該信號是否支持排除。SIGHUP( 1 ) ~ SIGSYS( 31 )之間的信號都是繼承自UNIX系統是不可靠信號。Linux系統根據POSIX標準定義了SIGRTMIN(33) ~ SIGRTMAX(64)之間的信號,它們都是可靠信號,也稱爲實時信號。

當導致產生信號的事件發生時,內核就產生一個信號。信號產生後,內核通常會在進程表中設置某種形的標誌。當內核設置了這個標誌,我們就說內核向一個進程遞送了一個信號。信號產生(generate)和遞送(delivery)之間的時間間隔,稱主信號未決(pending)

進程可以調用sigpending將信號設爲阻塞,如果爲進程產生一個阻塞信號,而對信號的動作是捕捉該信號(即不忽略信號),則內核將爲該進程的此信號保持爲未決狀態,直到該進程對此信號解除阻塞或者對此信號的響應更改爲忽略。如果在進程解除對某個信號的阻塞之前,這種信號發生了多次,那麼如果信號被遞送多次(即信號在未決信號隊列裏面排隊),則稱之爲可靠信號;只被遞送一次的信號稱爲不可靠信號。

2、信號的優先級

信號實質上是軟中斷,中斷有優先級,信號也有優先級。如果一個進程有多個未決信號,則對於同一個未決的實時信號,內核將按照發送的順序來遞送信號。如果存在多個未決信號,則值(或者說編號)越小的越先被遞送。如果即存在不可靠信號,又存在可靠信號(實時信號),雖然POSIX對這一情況沒有明確規定,但Linux系統和大多數遵循POSIX標準的操作系統一樣,將優先遞送不可靠信號。

三、進程對信號的響應

當信號發生時,用戶可以要求進程以下列3種方式之一對信號做出響應。

1、  捕捉信號:對於要捕捉的信號,可以爲其指定信號處理函數,信號發生時該函數自動被調用,在該函數內部實現對該信號的處理。

2、  忽略信號:大多數信號都可使用這種方式進行處理,但是SIGKILLSIGSTOP這兩個信號不能被忽略,同時這兩個信號也不能被捕獲和阻塞。此外,如果忽略某某些由硬件異常產生的信號(如非法存儲訪問或除以0),則進程的行爲是不可預測的。

3、  按照系統默認方式處理。大部分信號的默認操作是終止進程,且所有的實時信號的默認動作都是終止進程。

四、各種信號的默認處理情況

程序不可捕獲、阻塞或忽略的信號有:SIGKILL,SIGSTOP

不能恢復至默認動作的信號有:SIGILL,SIGTRAP

默認會導致進程流產的信號有:SIGABRTSIGBUSSIGFPESIGILLSIGIOTSIGQUITSIGSEGVSIGTRAPSIGXCPUSIGXFSZ

默認會導致進程退出的信號有:SIGALRMSIGHUPSIGINTSIGKILLSIGPIPESIGPOLLSIGPROFSIGSYSSIGTERMSIGUSR1SIGUSR2SIGVTALRM

默認會導致進程停止的信號有:SIGSTOPSIGTSTPSIGTTINSIGTTOU

默認進程忽略的信號有:SIGCHLDSIGPWRSIGURGSIGWINCH

 

五、信號處理函數與相關結構

        1、信號安裝

(1)、signal()
#include <signal.h>
void (*signal(int signum, void (*handler))(int)))(int);
如果該函數原型不容易理解的話,可以參考下面的分解方式來理解:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler));
第一個參數指定信號的值,第二個參數指定針對前面信號值的處理,可以忽略該信號(參數設爲SIG_IGN);可以採用系統默認方式處理信號(參數設爲SIG_DFL);也可以自己實現處理方式(參數指定一個函數地址)。
如果signal()調用成功,返回最後一次爲安裝信號signum而調用signal()時的handler值;失敗則返回SIG_ERR。

 

(2)、sigaction()
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

sigaction函數用於改變進程接收到特定信號後的行爲。該函數的第一個參數爲信號的值,可以爲除SIGKILL及SIGSTOP外的任何一個特定有效的信號(爲這兩個信號定義自己的處理函數,將導致信號安裝錯誤)。第二個參數是指向結構sigaction的一個實例的指針,在結構sigaction的實例中,指定了對特定信號的處理,可以爲空,進程會以缺省方式對信號處理;第三個參數oldact指向的對象用來保存原來對相應信號的處理,可指定oldact爲NULL。如果把第二、第三個參數都設爲NULL,那麼該函數可用於檢查信號的有效性。

 

      2、發送信號函數

       (1) int raise(int sig);  對當前進程發送指定信號

       (2) int pause(void);  將進程掛起等待信號

       (3) int kill(pid_t pid,int sig); 通過進程編號發送信號

       (4) unsigned int alarm(unsigned int seconds); 指定時間(秒)發送SIGALRM信號。 seconds 爲0 時取消所有已設置的alarm請求;

       (5)int sigqueue(pid_t pid,int sig,const union sigval val);類似於kill函數,多了附帶共用體 union sigval形數,將共用體中的成員 int sival_int 或 void *sival_ptr 的值傳遞給 信號處理函數中的定義類型 siginfo_t 中的 int si_int 或 void *si_ptr;

       (6)int setitimer(int which,const struct itimerval *value,struct itimerval *oldvalue);  可定時發送信號,根據which可指定三種信號類型:SIGALRM、SIGVTALRM 和 SIGPROF;作用時間也因which值不同而不同;struct itimerval 的成員 it_interval定義間隔時間,it_value 爲0時,使計時器失效;

        (7) void abort(void) 將造成進程終止;除非捕獲SIGABORT信號;  

 

         3、信號集及信號集操作

sigfillset(sigset_t *set); 設置所有的信號到set信號集中;
sigemptyset(sigset_t *set); 從set信號集中清空所有信號;
sigaddset(sigset_t *set,int sig);在set信號集中加入sig信號;
sigdelset(sigset_t *set,int sig);在set信號集中刪除sig信號;

         4、阻塞信號相關函數

          int sigprocmask(int how,const sigset_t *set,sigset_t *set);  根據how值,設置阻塞信號集,或釋放阻塞的信號集

          int sigpending(sigset_t *set); 獲取在阻塞中的所有信號;

          int sigsuspend(const sigset_t *set);    類似於 pause()函數!

 

發佈了35 篇原創文章 · 獲贊 14 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章