信號的基本概念
信號就是一個軟件中斷,能夠打斷進程的執行,讓進程處理信號的事件
信號種類:
1-31信號是不可靠信號:信號有可能會丟失(非實時信號)
編程
1.向進程發送非實時信號(該信號沒有被掛起),信號響應會嵌套(即正在響應某個函數時,有其它信號發來,進程會先去響應其它信號,結束後再繼續原來的任務)。 2.當進程正在響應某個信號時(該信號沒有被掛起),即響應函數正在執行的過程當中,有相同的n個信號相繼發來,進程不會嵌套; 當執行完響應函數後,進程只會執行n個信號中的一個。 3.對非實時信號,掛起的信號不會重複(即有n個相同的信號被掛起,進程只會執行一次)
34-64信號是可靠信號:信號不會丟失(實時信號)ide
1.向進程發送實時信號(該信號沒有被掛起),信號響應會嵌套。 2.當進程正在響應某個信號時(該信號沒有被掛起),即響應函數正在執行的過程當中,有相同的n個信號相繼發來,進程不會嵌套; 當執行完響應函數後,進程會繼續執行函數n次。 3.對實時信號,掛起的信號能夠重複(即有n個相同的信號被掛起,進程會執行n次)
若是進程的掛起信號中含有實時和非實時信號,那麼進程優先響應實時信號並會從大到小依次響應,而非實時信號沒有固定的次序,甚至某個非實時信號會被丟失(這可說明爲何非實時信號被叫作不可靠信號)。
信號產生方式:
1.硬件產生:ctrl+c(SIGINT),ctrl+z(SIGTSTP),ctrl+|(SEGOUIT)
2.軟件產生:kill -信號號碼+進程號
eg:kill -9 12345
kill函數:kill(信號號, SIGINT);//給給定信號號的進程發送SIGINT信號
abort函數:void abort();給當前進程發送SIGABRT信號
raise函數:int raise(int sig);給當前進程發送sig信號
alarm函數:unsigned int alarm(unsigned int seconds);
seconds秒以後,給調用進程發送SIGALRM信號
seconds若爲0,則表示取消上一個定時器
返回值:上一個定時器的剩餘時間
函數
alarm(3);//定時3秒 sleep(1);//表示alarm會響應2秒 alarm(0);//取消3秒定時器
core dumped:核心轉儲文件命名格式:core.pid
ulimit -a 查看
ulimit -c 設置core文件最大大小,單位爲kb ulimit -c 1024
調試方法:gdb ./main->core.file core.pid ->bt
信號的生命週期
信號在進程當中的註冊
非可靠信號(1~31):
若是待註冊的信號,在pending位圖當中已經存在了,則再也不去添加當前信號(意味着不增長sigqueue節點)
若是待註冊的信號,在pending位圖中不存在,將pending位圖當中的對應的bit位置位1,而後添加sigqueue節點
可靠信號(34~64):
若是待註冊的信號,在pending位圖當中存在(意味着對應的bit位爲1),另外增長sigqueue節點(意味着這個信號也會被處理)
若是待註冊的信號,在pending位圖當中不存在,則更改pending位圖中對應的bit位,而且增長sigqueue節點
信號在進程當中的註銷
1.非可靠信號
將pending位圖當中的對應的bit位置爲0,而且將sigqueue節點刪除
2.可靠信號
若是註銷的信號,存在的sigqueue節點只有1個,則將pending位圖當中的對應的bit位置爲0,而且將sigqueue節點刪除
若是註銷的信號,存在sigqueue節點有多個,不能將pending位圖當中對應的bit位置爲0,而是刪除一個sigqueue節點
操作系統
信號的處理
默認處理方式---SIG_DFL
忽略處理方式---SIG_IGN
自定義處理方式
調試
signal函數:能夠重置當前操做系統對信號的處理方式code
typedef void (* sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
生命週期
#include <stdio.h> #include <unistd.h> #include <signal.h> void sigbackfunc(int sig) { printf("sig : [%d]\n", sig); signal(2, SIG_DFL);//遇到2號信號以後,忽略處理 } int main() { signal(SIGINT, sigbackfunc);//收到2號信號以後,自定義處理(轉到sigbackfunc函數) while(1) { printf("hello~\n"); sleep(1); } return 0; }
sigaction函數進程
int sigaction(int signum,const struct sigaction act,struct sigaction oldact);
act:表示將當前信號修改爲一種處理方式,讓操做系統接收到這個信號的時候,調用哪個函數處理
oldact:表示以前操做系統對收到該信號的時候 的處理方式
事件
#include <stdio.h> #include <signal.h> #include <unistd.h> void sigbackfunc(int sig) { printf("%d\n", sig); } int main() { struct sigaction newact; struct sigaction oldact; newact.sa_handler = sigbackfunc; newact.sa_flags = 0; sigemptyset(&newact.sa_mask); sigaction(2, &newact, &oldact); while(1) { printf("hello\n"); sleep(1); } return 0; }
信號捕捉流程資源
信號阻塞
信號阻塞不是說信號不能被註冊,而是說,從操做系統在判斷pending位圖是發現接受某個信號了,去查找block位圖對應的bit位
若是block對應的位爲1,則不處理該信號,sigqueue節點仍是在的
若是block對應的位置爲0,則處理該信號
int sigprocmask(int how,const sigset_t set,sigset_t oldset);
how:SIG_BLOCK-->設置某個信號爲阻塞狀態,block(new)=block(old) | set
SIG_UNBLOCK-->設置某個信號爲非阻塞狀態,block(new)=block & (~set)
SIG_SETMASK-->設置新位圖block=set
block:0000 0000 set : 1111 1111 (阻塞信號) block(new)=block(old) | set 1111 1111 (非阻塞信號)block(new)=block & (~set) 1111 1111 & (0000 0000)-->0000 0000
注意
9號,19號信號是不能設置爲阻塞的
#include <stdio.h> #include <unistd.h> #include <signal.h> void sigcallback(int sig) { printf("sig : [%d]\n", sig); } int main() { signal(2, sigcallback); signal(40, sigcallback); //block位圖設置一下,也就是阻塞某些信號 //int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); sigset_t set, oldset; sigemptyset(&set); sigemptyset(&oldset); //給set位圖編程全1 //int sigfillset(sigset_t *set); sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); getchar(); sigprocmask(SIG_UNBLOCK, &set, NULL); while(1) { ; } return 0; }
競態條件
程序的不一樣的執行流,執行順序的不一樣,會致使程序結果的不一樣,這種咱們稱之爲競態條件
重入:不一樣的執行流能夠訪問一樣的資源(代碼) 可重入:不一樣的執行流能夠訪問一樣的資源,不會對程序的結果產生影響 不可重入:不一樣的執行流能夠訪問一樣的資源,可是對程序的結果產生影響 不可重入場景:全局變量,malloc和free ,絕大多數的庫函數
SIGCHLD--17號信號
SIGCHLD信號的默認行爲是不處理,咱們能夠更改掉SIGCHLD信號的默認處理函數,讓收到該信號的時候調用自定義的函數去完成進程等待,從而父進程就能夠完成本身的邏輯,而不用調用wait進行阻塞了,意味着了,咱們能夠在回調函數中調用wait
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> void sigcallback(int sig) { printf("sig : %d\n", sig); wait(NULL); } int main() { signal(SIGCHLD, sigcallback); pid_t pid = fork(); if(pid < 0) { return pid; } else if(pid == 0) { //child printf("i am child\n"); sleep(3); exit(1); } else { //wait while(1) { printf("我不聽~~~\n"); sleep(1); } } return 0; }