Linux信號(signal)機制
一、信號類型信號(signal)是一種軟中斷,信號機制是進程間通信的一種方式,采用異步通信方式
Linux系統共定義了64種信號,分為兩大類:可靠信號與不可靠信號,前32種信號為不可靠信號,后32種為可靠信號。
1.1 概念不可靠信號: 也稱為非實時信號,不支持排隊,信號可能會丟失, 比如發送多次相同的信號, 進程只能收到一次. 信號值取值區間為1~31;
可靠信號: 也稱為實時信號,支持排隊, 信號不會丟失, 發多少次, 就可以收到多少次. 信號值取值區間為32~64
在終端,可通過kill -l查看所有的signal信號
| 1 | SIGHUP | 掛起 | |
| 2 | SIGINT | 中斷 | |
| 3 | SIGQUIT | 退出 | |
| 4 | SIGILL | 非法指令 | |
| 5 | SIGTRAP | 斷點或陷阱指令 | |
| 6 | SIGABRT | abort發出的信號 | |
| 7 | SIGBUS | 非法內存訪問 | |
| 8 | SIGFPE | 浮點異常 | |
| 9 | SIGKILL | kill信號 | 不能被忽略、處理和阻塞 |
| 10 | SIGUSR1 | 用戶信號1 | |
| 11 | SIGSEGV | 無效內存訪問 | |
| 12 | SIGUSR2 | 用戶信號2 | |
| 13 | SIGPIPE | 管道破損,沒有讀端的管道寫數據 | |
| 14 | SIGALRM | alarm發出的信號 | |
| 15 | SIGTERM | 終止信號 | |
| 16 | SIGSTKFLT | 棧溢出 | |
| 17 | SIGCHLD | 子進程退出 | 默認忽略 |
| 18 | SIGCONT | 進程繼續 | |
| 19 | SIGSTOP | 進程停止 | 不能被忽略、處理和阻塞 |
| 20 | SIGTSTP | 進程停止 | |
| 21 | SIGTTIN | 進程停止,后臺進程從終端讀數據時 | |
| 22 | SIGTTOU | 進程停止,后臺進程想終端寫數據時 | |
| 23 | SIGURG | I/O有緊急數據到達當前進程 | 默認忽略 |
| 24 | SIGXCPU | 進程的CPU時間片到期 | |
| 25 | SIGXFSZ | 文件大小的超出上限 | |
| 26 | SIGVTALRM | 虛擬時鐘超時 | |
| 27 | SIGPROF | profile時鐘超時 | |
| 28 | SIGWINCH | 窗口大小改變 | 默認忽略 |
| 29 | SIGIO | I/O相關 | |
| 30 | SIGPWR | 關機 | 默認忽略 |
| 31 | SIGSYS | 系統調用異常 |
對于signal信號,絕大部分的默認處理都是終止進程或停止進程,或dump內核映像轉儲。 上述的31的信號為非實時信號,其他的信號32-64 都是實時信號。
二、信號產生信號來源分為硬件類和軟件類:
2.1 硬件方式用戶輸入:比如在終端上按下組合鍵ctrl+C,產生SIGINT信號;
硬件異常:CPU檢測到內存非法訪問等異常,通知內核生成相應信號,并發送給發生事件的進程;
通過系統調用,發送signal信號:kill(),raise(),sigqueue(),alarm(),setitimer(),abort()
kernel,使用 kill_proc_info()等
native,使用 kill() 或者raise()等
java,使用 Procees.sendSignal()等
在進程task_struct結構體中有一個未決信號的成員變量 struct sigpending pending。每個信號在進程中注冊都會把信號值加入到進程的未決信號集。
非實時信號發送給進程時,如果該信息已經在進程中注冊過,不會再次注冊,故信號會丟失;
實時信號發送給進程時,不管該信號是否在進程中注冊過,都會再次注冊。故信號不會丟失;
非實時信號:不可重復注冊,最多只有一個sigqueue結構;當該結構被釋放后,把該信號從進程未決信號集中刪除,則信號注銷完畢;
實時信號:可重復注冊,可能存在多個sigqueue結構;當該信號的所有sigqueue處理完畢后,把該信號從進程未決信號集中刪除,則信號注銷完畢;
內核處理進程收到的signal是在當前進程的上下文,故進程必須是Running狀態。當進程喚醒或者調度后獲取CPU,則會從內核態轉到用戶態時檢測是否有signal等待處理,處理完,進程會把相應的未決信號從鏈表中去掉。
4.1 處理時機signal信號處理時機: 內核態 -> signal信號處理 -> 用戶態:
在內核態,signal信號不起作用;
在用戶態,signal所有未被屏蔽的信號都處理完畢;
當屏蔽信號,取消屏蔽時,會在下一次內核轉用戶態的過程中執行;
進程對信號的處理方式: 有3種
默認 接收到信號后按默認的行為處理該信號。 這是多數應用采取的處理方式。
自定義 用自定義的信號處理函數來執行特定的動作
忽略 接收到信號后不做任何反應。
進程處理某個信號前,需要先在進程中安裝此信號。安裝過程主要是建立信號值和進程對相應信息值的動作。
信號安裝函數
signal():不支持信號傳遞信息,主要用于非實時信號安裝;
sigaction():支持信號傳遞信息,可用于所有信號安裝;
其中 sigaction結構體
sa_handler:信號處理函數
sa_mask:指定信號處理程序執行過程中需要阻塞的信號;
sa_flags:標示位
SA_RESTART:使被信號打斷的syscall重新發起。
SA_NOCLDSTOP:使父進程在它的子進程暫停或繼續運行時不會收到 SIGCHLD 信號。
SA_NOCLDWAIT:使父進程在它的子進程退出時不會收到SIGCHLD信號,這時子進程如果退出也不會成為僵 尸進程。
SA_NODEFER:使對信號的屏蔽無效,即在信號處理函數執行期間仍能發出這個信號。
SA_RESETHAND:信號處理之后重新設置為默認的處理方式。
SA_SIGINFO:使用sa_sigaction成員而不是sa_handler作為信號處理函數。
函數原型:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
signum:要操作的signal信號。
act:設置對signal信號的新處理方式。
oldact:原來對信號的處理方式。
返回值:0 表示成功,-1 表示有錯誤發生。
kill():用于向進程或進程組發送信號;
sigqueue():只能向一個進程發送信號,不能像進程組發送信號;主要針對實時信號提出,與sigaction()組合使用,當然也支持非實時信號的發送;
alarm():用于調用進程指定時間后發出SIGALARM信號;
setitimer():設置定時器,計時達到后給進程發送SIGALRM信號,功能比alarm更強大;
abort():向進程發送SIGABORT信號,默認進程會異常退出。
raise():用于向進程自身發送信號;
信號集操作函數
sigemptyset(sigset_t *set):信號集全部清0;
sigfillset(sigset_t *set): 信號集全部置1,則信號集包含linux支持的64種信號;
sigaddset(sigset_t *set, int signum):向信號集中加入signum信號;
sigdelset(sigset_t *set, int signum):向信號集中刪除signum信號;
sigismember(const sigset_t *set, int signum):判定信號signum是否存在信號集中。
信號阻塞函數
sigprocmask(int how, const sigset_t *set, sigset_t *oldset)); 不同how參數,實現不同功能
SIG_BLOCK:將set指向信號集中的信號,添加到進程阻塞信號集;
SIG_UNBLOCK:將set指向信號集中的信號,從進程阻塞信號集刪除;
SIG_SETMASK:將set指向信號集中的信號,設置成進程阻塞信號集;
sigpending(sigset_t *set)):獲取已發送到進程,卻被阻塞的所有信號;
sigsuspend(const sigset_t *mask)):用mask代替進程的原有掩碼,并暫停進程執行,直到收到信號再恢復原有掩碼并繼續執行進程。
Linux信號(signal)機制 - JackPeng博客 (yuanfentiank789.github.io)
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。











