1、基本概念
一、中斷:停止、暫停當前正在執行的進程,轉而去執行其餘的任務
硬中斷:來自硬件設備的中斷
軟中斷:來自其餘程序的中斷
二、信號:信號是一種軟中斷,能夠把他看做是進程與進程、內核與進程通訊的一種方式,它爲進程的異步執行,提供了技術支持
三、常見的信號
SIGINT(2) 終端中斷符信號 用戶按中斷鍵(Ctrl+C),產生此信號,並送至前臺進程組的全部進程 終止
SIGQUIT(3) 終端退出符信號 用戶按退出鍵(Ctrl+\),產生此信號,並送至前臺進程組的全部進程 終止+core
SIGABRT(6) 異常終止信號 調用abort函數,產生此信號 終止+core
SIGFPE(8) 算術異常信號 表示一個算術運算異常,例如除以0、浮點溢出等 終止+core
SIGKILL(9) 終止信號 不能被捕獲或忽略。經常使用於殺死進程 終止
SIGSEGV(11) 段錯誤信號 試圖訪問未分配的內存,或向沒有寫權限的內存寫入數據 終止+core
SIGALRM(14) 鬧鐘信號 以alarm函數設置的計時器到期,或以setitimer函數設置的間隔時間到期,均產生此信號 終止
SIGCHLD(17) 子進程狀態改變信號 在一個進程終止或中止時,將此信號發送給其父進程 忽略
SIGCONT(18) 使中止的進程繼續 向處於中止狀態的進程發送此信號,令其繼續運行 繼續/忽略
SIGSTOP(19) 中止信號 不能被捕獲或忽略。中止一個進程 中止進程
SIGTSTP(20) 終端中止符信號 用戶按中止鍵(Ctrl+Z),產生此信號,並送至前臺進程組的全部進程 中止進程
四、不可靠的信號(非實時)
a、編號小於SIGRGMI(34)的信號都是不可靠的,這些信號是創建在早期的信號機制上的,一個事件的發生可能會產生屢次信號
b、不可靠信號不支持排除,在接收信號的時候可能會丟失,若是一個信號發送給進程屢次,它可能只接收到一次,其它的可能就丟失了
c、進程在處理這種信號的時候,哪怕設置的信號處理函數,當信號處理函數執行完畢後,會再次恢復成默認的信號處理方式
五、可靠信號(實時)
a、位於[SIGRGMI(34),SIGRTMAX(64)]區間的都是可靠信號
b、可靠信號支持排隊,不會丟失
c、不管是可靠信號仍是不可靠信號都是經過:kill、signal、sigqueue、sigaction進行處理
六、信號的來源
硬件來源:
鍵盤:Ctrl + c、Ctrl + \、Ctrl + z
驅動:硬件設備被激活、使用、失效
內存:非法訪問內存
軟件來源:
命令:kill、killall
函數:kill/raise/alarm/setitimer/
七、信號的處理方式
a、忽略
b、終止
c、終止+core
core dump 把內存的使用狀況仍出來
core文件是一種二進制文件,須要一些高度工具才能解析出來(gdb)
一、gcc -g core.c -> 生成帶調試信息的可執行文件
二、運行可執行文件
三、gdb ./a.out core 程序會中止在產生錯誤的位置
ubuntu默認不產生core文件,須要使用命令設置:ulimit -c unlimited
d、捕獲並處理
2、信號的捕獲並處理 //signal.c
#include <signal.h>ubuntu
typedef void (*sighandler_t)(int);異步
sighandler_t signal(int signum, sighandler_t handler);
功能:向內核註冊一個信號處理函數
signum:信號的編號,能夠直接寫數字,也可使用系統提供的宏
handler:信號的處理方式
函數指針
SIG_IGN 忽略信號
SIG_DFL 恢復信號默認的處理方式
返回值:是以前信號的處理方式
函數指針、SIG_IGN、SIG_DFl、SIG_ERR
一、在有些系統中向內核註冊的信號處理函數只執行一次(在執行前就被恢復成默認的處理方式),若是想持續處理信號,能夠在每次的處理函數結束時再次註冊
二、SIGKILL、SIGSTOP不能被捕獲也不能被忽略di
三、普通用戶只能給本身的進程發信號,root用戶能夠給任意進程發送信號
3、子進程的信號處理
一、經過fork建立的子進程會繼承父進程的信號處理方式 //fork_signal.c
二、經過vfork+exec建立的子進程不會繼承父進程的信號處理方式,會恢復成默認的函數
4、信號的發送
一、鍵盤
Ctrl+c 終端中斷信號
Ctrl+z 終端暫停信號,fg命令再次開啓
Ctrl+\ 終端退出信號
二、錯誤產生的信號
除0
非法內存訪問
硬件總線
三、命令產生的信號
kill -信號 進程號
killall -信號 程序名(殺死全部同名的進程)
四、函數產生的信號
int kill(pid_t pid, int sig);
功能:向指定的進程發送信號
pid:與waitpid同樣
sig:信號碼
0表示空信號,不會向進程發送信號,可是會測試是否能向pid發送信號,這樣能夠檢測一個進程是否存在,返回-1表示進程不存在,errno爲ESRCH
返回值:-1,說明進程不存在
int raise(int sig);
功能:向本身發送信號工具
5、pause
#include <unistd.h>
int pause(void);
功能:休眠
一、進程調用了pause函數後會入睡眠狀態,直到有信號把它叫醒(不被忽略的信號)
二、當信號來臨後,先執行信號處理函數,信號處理函數結束後pause再返回
三、pause函數要麼不返回(一直睡眠),要麼返回-1,而且修改errno的值
四、從功能上來說它至關於沒有時間限制的sleep函數
6、sleep
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
功能:使用調用的進程睡眠seconds秒
一、調用sleep的進程若是沒有睡眠足夠的秒數,除非收到信號纔會返回
二、sleep的返回值是0,或剩餘睡眠的妙數
三、至關於有時間限制的pause
int usleep(useconds_t usec);
功能:睡眠usec微秒
1秒=1000毫秒=1000000微秒
它是一種更精確的睡眠函數
7、alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:定時一個鬧鐘信號
一、讓內核向調用它的進程,在secongds秒後發送一個時鐘信號SIGALRM信號
二、SIGALRM信號的默認處理方式是直接退出
8、信號集和信號屏蔽
一、信號集:
多個信號的集合,sigset_t
由128個二進制位組成,每一個二進制位表示一個信號
#include <signal.h>
int sigemptyset(sigset_t *set);
功能:清空信號集測試
int sigfillset(sigset_t *set);
功能:填滿信號集
int sigaddset(sigset_t *set, int signum);
功能:從信號集中添加信號
int sigdelset(sigset_t *set, int signum);
功能:從信號集中刪除信號
int sigismember(const sigset_t *set, int signum);
功能:測試信號集中是否有某個信號
返回值:有返回1,沒有返回0,失敗返回-1
二、屏蔽信號集中的信號
每一個進程都有一個信號掩碼(signal mask),它就是一個信號集,裏面包含了進程所屏蔽的信號
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:設置進程的信號掩碼(信號屏蔽碼)
how:修改信號掩碼的方式
SIG_BLOCK:向信號掩碼中添加信號
SIG_UNBLOCK:從信號掩碼中刪除信號
SIG_SETMASK:用新的信號集替舊的信號掩碼
newset:新添加、刪除、替換的信號集,也能夠爲空
oldset:獲取舊的信號掩碼
當newset爲空時,就是在備份信號掩碼
當進程執行一些敏感操做時不但願被打擾(原子操做),此時須要屏蔽信號
屏蔽信號的目的不是爲了避免接收信號,而是延遲接收,當處理完要作的事情後,應該把屏蔽的信號還原
當信號屏蔽時發生的信號會記錄一次,這個信號設置爲末決狀態,當信號屏蔽結束後,會再發送一次
不可靠信號在信號屏蔽期間不管信號發送多少次,信號解除屏蔽後,只發送一次
可靠信號在信號屏蔽期間發生的信號會排隊記錄,在信號接觸屏蔽後逐個處理
在執行信號處理函數時,會默認把當前處理的信號屏蔽掉,執行完成後再恢復
int sigpending(sigset_t *set);
功能:獲取未決狀態的信號
9、信號處理sigaction
#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 *); //信號處理函數指針 須要使用sigqueue發送信號
sigset_t sa_mask; //信號屏蔽碼
int sa_flags;
SA_NOCLDSTOP:忽略SIGCHLD
SA_NODEFER/SA_NOMASK:處理時不屏蔽信號
SA_RESETHAND:處理完信號後,恢復默認處理方式
SA_RESTART:當信號處理函數中斷的系統調用,則重啓
SA_SIGINFO:用sa_sigaction處理信號
void (*sa_restorer)(void);//保留
};
int sigqueue(pid_t pid, int sig, const union sigval value);指針