信號由三種處理方式:bash
若是信號的處理動做是用戶自定義函數,在信號遞達時就調用這個自定義函數,這稱爲捕捉信號。併發
進程收到一個信號後不會被當即處理,而是在恰當時機進行處理!即內核態返回用戶態以前 !函數
可是因爲信號處理函數的代碼在用戶空間,因此這增長了內核處理信號捕捉的複雜度。spa
給某一個進程的某一個信號(標號爲signum)註冊一個相應的處理函數,即對該信號的默認處理動做進行修改,修改成handler函數指向的方式;.net
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
//即:
void (*signal(int, void(*)(int)))(int);
signal函數接受兩個參數:一個整型的信號編號,以及一個指向用戶定義的信號處理函數的指針。 3d
此外,signal函數的返回值是一個指向調用用戶定義信號處理函數的指針。指針
sigaction函數能夠讀取和修改與指定信號相關聯的處理動做。rest
#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是指定信號的編號。htm
處理方式:
(注:後兩個參數都是輸入輸出型參數!)
將sa_handler三種可選方式:
(注:這是一個回調函數,不是被main函數調用,而是被系統所調用)
當某個信號的處理函數被調用時,內核自動將當前信號加入進程的信號屏蔽字,當信號處理函數返回時自動恢復原來的信號屏蔽字,這樣就保證了在處理某個信號時,若是這種信號再次產生,那麼 它會被阻塞到當前處理結束爲止。
pause函數使調用進程掛起直到有信號遞達!
#include <unistd.h> int pause(void);
處理方式:
因此pause只有出錯的返回值(相似exec函數家族)。錯誤碼EINTR表示「被信號中斷」。
進入sig_alrm函數時SIGALRM信號被自動屏蔽,從sig_alrm函數返回時SIGALRM信號自動解除屏蔽。而後自動執行特殊的系統調用sigreturn再次進入內核,以後再返回用戶態繼續執行進程的主控制流程(main函數調用的mytest函數)。
pause函數返回-1,而後調用alarm(0)取消鬧鐘,調用sigaction恢復SIGALRM信號之前的處理 動做。
/************************************************************************* > File Name: Pause.c > Author:Lynn-Zhang > Mail: iynu17@yeah.net > 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信號則執行其默認處理動做即終止進程!