轉載:http://blog.csdn.net/beginning1126/article/details/8680757
今天看到unp時發現之前對signal到理解實在淺顯,今天拿來單獨學習討論下。
signal,此函數相對簡單一些,給定一個信號,給出信號處理函數則可,當然,函數簡單,其功能也相對簡單許多,簡單給出個函數例子如下:
- ?1?#include?<signal.h>??
- ?2?#include?<stdio.h>??
- ?3?#include?<unistd.h>??
- ?4???
- ?5?void?ouch(int?sig)??
- ?6?{??
- ?7?????printf("I?got?signal?%d\n",?sig);??
- ?8???????
- ?9???????
- 10???
- 11?}??
- 12???
- 13???
- 14???
- 15?int?main()??
- 16?{??
- 17?????(void)?signal(SIGINT,?ouch);??
- 18???
- 19?????while(1)??
- 20?????{??
- 21?????????printf("hello?world...\n");??
- 22?????????sleep(1);??
- 23?????}??
- 24?}??
當然,實際運用中,需要對不同到signal設定不同的到信號處理函數,SIG_IGN忽略/SIG_DFL默認,這倆宏也可以作為信號處理函數。同時SIGSTOP/SIGKILL這倆信號無法捕獲和忽略。注意,經過實驗發現,signal函數也會堵塞當前正在處理的signal,但是沒有辦法阻塞其它signal,比如正在處理SIG_INT,再來一個SIG_INT則會堵塞,但是來SIG_QUIT則會被其中斷,如果SIG_QUIT有處理,則需要等待SIG_QUIT處理完了,SIG_INT才會接著剛才處理。
sigaction,這個相對麻煩一些,函數原型如下:
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
函數到關鍵就在于struct sigaction
- stuct?sigaction??
- {??
- ??????void?(*)(int)?sa_handle;??
- ??????sigset_t?sa_mask;??
- ??????int?sa_flags;??
- }??
- 1?#include?<signal.h>??
- ??2?#include?<stdio.h>??
- ??3?#include?<unistd.h>??
- ??4???
- ??5???
- ??6?void?ouch(int?sig)??
- ??7?{??
- ??8?????printf("oh,?got?a?signal?%d\n",?sig);??
- ??9???
- ?10?????int?i?=?0;??
- ?11?????for?(i?=?0;?i?<?5;?i++)??
- ?12?????{??
- ?13?????????printf("signal?func?%d\n",?i);??
- ?14?????????sleep(1);??
- ?15?????}??
- ?16?}??
- ?17???
- ?18???
- ?19?int?main()??
- ?20?{??
- ?21?????struct?sigaction?act;??
- ?22?????act.sa_handler?=?ouch;??
- ?23?????sigemptyset(&act.sa_mask);??
- ?24?????sigaddset(&act.sa_mask,?SIGQUIT);??
- ?25???????
- ?26???????
- ?27?????act.sa_flags?=?0;??
- ?28???
- ?29?????sigaction(SIGINT,?&act,?0);??
- ?30???
- ?31???
- ?32?????struct?sigaction?act_2;??
- ?33?????act_2.sa_handler?=?ouch;??
- ?34?????sigemptyset(&act_2.sa_mask);??
- ?35?????act.sa_flags?=?0;??
- ?36?????sigaction(SIGQUIT,?&act_2,?0);??
- ?37???
- ????????while(1)??
- ????????{??
- ?????????????sleep(1);??
- ????????}??
- ?38?????return;??
- ??
- ????}??
1. 阻塞,sigaction函數有阻塞的功能,比如SIGINT信號來了,進入信號處理函數,默認情況下,在信號處理函數未完成之前,如果又來了一個SIGINT信號,其將被阻塞,只有信號處理函數處理完畢,才會對后來的SIGINT再進行處理,同時后續無論來多少個SIGINT,僅處理一個SIGINT,sigaction會對后續SIGINT進行排隊合并處理。
2. sa_mask,信號屏蔽集,可以通過函數sigemptyset/sigaddset等來清空和增加需要屏蔽的信號,上面代碼中,對信號SIGINT處理時,如果來信號SIGQUIT,其將被屏蔽,但是如果在處理SIGQUIT,來了SIGINT,則首先處理SIGINT,然后接著處理SIGQUIT。
3.?sa_flags如果取值為0,則表示默認行為。還可以取如下倆值,但是我沒覺得這倆值有啥用。
SA_NODEFER,如果設置來該標志,則不進行當前處理信號到阻塞
SA_RESETHAND,如果設置來該標志,則處理完當前信號后,將信號處理函數設置為SIG_DFL行為
下面單獨來討論一下信號屏蔽,記住是屏蔽,不是消除,就是來了信號,如果當前是block,則先不傳遞給當前進程,但是一旦unblock,則信號會重新到達。
- #include?<signal.h>??
- #include?<stdio.h>??
- #include?<unistd.h>??
- ??
- ??
- ??
- static?void?sig_quit(int);??
- ??
- int?main?(void)?{??
- ????sigset_t?new,?old,?pend;??
- ??????
- ????signal(SIGQUIT,?sig_quit);??
- ??
- ????sigemptyset(&new);??
- ????sigaddset(&new,?SIGQUIT);??
- ????sigprocmask(SIG_BLOCK,?&new,?&old);??
- ??
- ????sleep(5);??
- ??
- ????printf("SIGQUIT?unblocked\n");??
- ????sigprocmask(SIG_SETMASK,?&old,?NULL);??
- ??
- ????sleep(50);??
- ????return?1;??
- }??
- ??
- static?void?sig_quit(int?signo)?{??
- ????printf("catch?SIGQUIT\n");??
- ????signal(SIGQUIT,?SIG_DFL);??
- }??
gcc -g -o mask mask.c?
./mask
========這個地方按多次ctrl+\
SIGQUIT unblocked
catch SIGQUIT
Quit (core dumped)
======================
注意觀察運行結果,在sleep的時候,按多次ctrl+\,由于sleep之前block了SIG_QUIT,所以無法獲得SIG_QUIT,但是一旦運行sigprocmask(SIG_SETMASK, &old, NULL);則unblock了SIG_QUIT,則之前發送的SIG_QUIT隨之而來。
由于信號處理函數中設置了DFL,所以再發送SIG_QUIT,則直接coredump。