Unix環境高級編程筆記 :十、信號

信號是軟件中斷,信號提供了一種處理異步事件的方法。
一、信號概念
    每一個信號都有一個名字,這些名字都以三個字符SIG開頭。
    SIGABRT是夭折信號,當進程調用abort函數時產生這種信號
    SIGALRM是鬧鐘信號,當由alarm函數設置的計時器超時後產生此信號。
 
    在頭<signal.h>中,這些信號都被定義爲正整數(信號編號).
 
    不少條件能夠產生信號 :
    a)當用戶按某些終端鍵時,引起終端產生信號
        ctrl+c產生中斷信號(SIGINT)
    b)硬件異常產生信號:除數爲0、無效內存引用
        對執行一個無效內存引用的進程產生SIGSEGV
    c)進程調用kill(2)函數可將信號發送給另外一個進程或進程組
    d)kill(1)命令將信號發送給其餘進程
    e)當檢測到某種軟件條件已經發生,並應將其通知有關進程時也產生信號。
 
    信號是異步事件,產生信號的事件對進程而言是隨機出現的。進程不能簡單的測試一個變量來判斷是否出現一個信號,而是必須告訴內核
    「在此信號出現時,請執行下列操做。」
 
    能夠要求內核在某個信號出現時按照下列三種方式之一進行處理,咱們稱之爲信號的處理
    (1)忽略此信號
        二種信號決不能被忽略:SIGKILL SIGSTOP
    (2)捕捉信號
    (3)執行系統默認動做
        每一種信號的默認動做。注,針對大多數信號的系統默認動做是終止進程。
 
    
    在「默認動做」列中,「終止+core」表示在進程當前工做目錄的core文件中複製該進程的存儲映象
 
二、signal
    #include <signal.h>
    void (*signal(int signo,void (*func)(int))) (int);
    
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
static void sig_usr(int signo);
 
int main(int argc, char **argv) {
if(signal(SIGUSR1,sig_usr) == SIG_ERR)
printf("signal error");
if(signal(SIGUSR2,sig_usr) == SIG_ERR)
printf("signal error");
 
for(;;) {
pause();
}
}
 
static void sig_usr(int signo) {
if(signo == SIGUSR1) {
printf("recived sigusr1");
}
if(signo == SIGUSR2) {
printf("recived sigusr2");
}
printf("recived %d",signo);
}
 
 
kill -SIGUSR1 11251
kill -SIGUSR2 11251
 
程序啓動:
1)當執行一個程序時,全部信號的狀態都是系統默認或忽略,一般全部信號都被設置爲它們的默認動做,除非調用exec的進程忽略該信號。
    
     一個具體的例子是一個交互式shell如何處理針對後臺進程的中斷和退出信號
    cc main.c &
    shell自動將後臺進程對中斷和退出信號的處理方式設置爲忽略。因而按中斷鍵時不會影響到後臺進程。
 
    不少捕捉這二個信號的交互式程序具備下列形式的代碼 :
    void sig_int(int),sig_quit(int);
    
    if(signal(SIGINT,SIG_IGN) != SIG_IGN)
        signal(SIGINT,sig_int);
    if(signal(SIGQUIT,SIG_IGN) != SIG_IGN)
        signal(SIGQUIT,sig_quit);
 
2)進程建立
    當一個進程調用fork時,其子進程繼承父進程的信號處理方式。由於子進程在開始時複製了父進程的存儲映像,因此信號捕捉函數的地址在子進程中是有意義
 
 
三、可重入函數
    進程捕捉到信號並對其進行處理時,進程正在執行的指令序列就被信號處理程序臨時中斷,它首先執行該信號處理程序中的指令。
若是從信號處理程序返回,則繼續執行在捕捉到信號時進程正執行的正常指令序列。
 
若信號處理程序中調用一個不可重入函數,則其結果是不可預見的。
 
四、可靠信號術語
    1)當引起信號的事件發生時,爲進程產生一個信號。可件能夠是硬件異常、軟件條件(alarm計時器超時)、終端產生的信號或調用kill。
    2)當對信號採起了這種動做時,咱們說向進程遞送了一個信號。
    3)在信號產生(generation)和遞送(delivery)之間的時間間隔內,稱信號是未決的(pending)
    4)進程能夠選用信號遞送阻塞
    5)進程調用sigpending判斷哪些信號是設置爲阻塞並處於未決狀態
    6)每一個進程都有一個信號屏蔽字(signal mask),它規定了當前要阻塞遞送到該進程的信號集。
    7)sigset_t,保存一個信號集,信號屏蔽字就存放在這些信號集中
 
 
五、kill raise
kill函數將信號發送給進程或進程組。raise函數則容許進程向自身發送信號
#include <signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
 
raise(signo) 等價於kill(getpid(),signo);
 
pid>0    將該信號發送給進程ID爲pid的進程
pid==0 將該信號發送給與發送進程屬於同一進程組的全部進程
pid<0    將該信號發送給其進程組ID等於pid的絕對值,並且發送進程具備向其發送信號的權限。
pid==-1將該信號發送給發送進程有權限向它們發送信號的系統上的全部進程。
 
六、alarm和pause
    使用alarm函數能夠設置一個計時器,在未來某個指定的時間該計時器會超時。當計時器超時時,產生SIGALRM信號。
    若是不忽略或不捕捉此信號,則其默認動做是終止調用該alarm函數的進程。
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
參數seconds的值是秒數,通過了指定的seconds秒後產生信號SIGALRM。
    
pause函數使調用進程掛起直至捕捉到一個信號。
#incude <unistd.h>
int pause(void);
 
七、信號集
    咱們須要有一個能表示多個信號---信號集(signal set)的數據類型。
    sigset_t表示一個信號集
    
#include <signal.h>
int sigemptyset(sigset_t *set);         //初始化由set指向的信號集,清除其中全部信號            
int sigfillset(sigset_t *set);               //初始化由set指向的信號集,使其包括全部信號 
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
        
八、sigprocmask函數
    sigprocmask能夠檢測或更改其信號屏蔽字,或者在一個步驟中同時執行這二個操做。
    
#include <signal.h>
int sigprocmask(int how,const sigset_t *restrict set,siset_t #restrict oset);
 
九、sigpending
    sigpending函數返回信號集,其中的各個信號對於調用進程是阻塞的而不能遞送,於是也必定是當前未決的。
#include <signal.h>
int sigpending(sigset_t *set);
 
十、sigaction
    sigaction函數的功能是檢查或修改與指定信號相關的處理動做。 
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);
 
十一、sigsetjmp   siglongjmp
    用於非局部轉移的setjmp和longjmp,在信號處理程序中常常調用longjmp函數以返回到程序的主循環中,而不是從該處理程序返回。
 
    調用longjmp有一個問題,當捕捉到一個信號時,進入信號捕捉函數,此時當前信號被自動地加到進程的信號屏蔽字中。
這阻止了後來產生的這種信號中斷該信號處理程序。
    
       #include <setjmp.h>
 
       int sigsetjmp(sigjmp_buf env, int savesigs);
       void siglongjmp(sigjmp_buf env, int val);
    若是savemask非0,則sigsetjmp在env中保存進程的當前信號屏蔽字。
    調用setlongjmp時,若是帶非0 savemask的sigsetjmp調用已經保存了env,則siglongjmp從其中恢復保存的信號屏蔽字。
 
十二、sigsuspend
 
1三、abort
 
1四、system
 
1五、sleep
相關文章
相關標籤/搜索