1. 信號概述
何為信號:信號就是由用戶、系統或進程發送給目標進程的信息,以通知目標進程中某個狀態的改變或是異常。
信號產生:總體來說,其產生的條件有兩種,分別是:硬件和軟件原因,又稱為:硬中斷和軟中斷。可細分為如下幾種原因:
①系統終端Terminal中輸入特殊的字符來產生一個信號,比如按下:ctrl+\會產生SIGQUIT信號。
②系統異常。比如訪問非法內存和浮點數異常。
③系統狀態變化。如設置了alarm定時器,當該定時器到期時候會引起SIGVTALRM信號。
④調用了kill命令或是kill函數。
?
?
1. 1 系統如何處理信號
Linux系統對于接收到的信號(無論是硬中斷還是軟中斷)可以有三種處理方式:
(1)忽略此信號。SIG_IGN,該常數表示信號函數的忽略。在/usr/include/x86_64-linux-gnu/bits/signum.h
頭文件中有SIG_IGN的宏定義
?
#define SIG_IGN ((__sighandler_t) 1) /* 忽略信號 */
(2)執行系統默認的動作。SIG_DFL,該常數表示信號的默認值。對于大多數的系統來說,系統的默認動作就是終止該進程。在/usr/include/x86_64-linux-gnu/bits/signum.h
頭文件中有SIG_IGN的宏定義
#define SIG_DFL ((__sighandler_t) 0) /* 默認動作 */
?值得注意的是:Linux下的系統默認動作一般有如下幾種:
①結束進程(Term)
②忽略信號(Ignore)
③結束進程并生成核心轉儲文件(Core),該文件用于gdb后期調試
④暫停進程(Stop)
⑤繼續進程(Continue),如果進程被掛起,則恢復進程的運行。否則,忽略該信號。
(3)捕捉該信號。這里需要用戶自定義一個函數,來對產生的信號進行捕捉,而在這個函數中可執行用戶希望對這個事件進行的處理操作。
?
2. 使用signal函數捕捉信號
在處理由系統產生的一個信號時候,首先得對產生的該信號進行安裝登記,這樣才能對其進行處理。何為安裝登記呢?其實很好理解,好比你去圖書館借閱圖書,當你找到了喜歡的書籍后,再用借書卡去機器上面掃描登記,然后就可以帶走該書籍去閱讀了。這里的圖書相當于信號,用借書卡登記和對信號進行登記同個道理,處理信號相當于你將書籍帶離圖書館閱讀。Linux上有兩個函數都可用來對信號進行登記,分別是:signal和 sigaction 。
這兩個函數的區別:
(1)signal是在系統調用的基礎上實現,是庫函數,它有兩個參數,不支持信號傳遞信息,主要用于kill -l 中的前32個非實時信號的安裝。
(2)sigaction是較新的函數,(由sys_signal和sys_rt_sigaction兩個系統調用實現 ),有3個參數。支持信號傳遞信息,主要用來和sigqueue系統調用配合使用。
?
2.1 signal詳解
#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);
- 函數說明:設置信號處理方式。signal()會依參數signum指定的信號編號(0~64)來設置該信號 的處理函數。當指定的信號到底時,就會跳轉到參數handler指定的函數執行。
signal函數成功時返回一個函數指針,該函數指針的類似也是sighandler_t。返回值是前一次調用signal函數時傳入的函數指針,或者是信號signum對應的默認處理函數指針SIG_DFL(如果是第一次調用的話)
signal系統調用出錯時返回SIG_ERR并設置errno。
?
#define SIG_ERR ((__sighandler_t) -1) /* 錯誤返回 */
?代碼1
/************************************************************************** File Name: signal.cpp* Author: The answer* Function: Other * Mail: 2412799512@qq.com * Created Time: 2018年05月13日 星期四 18時47分11秒************************************************************************/#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
using namespace std;void sig_handler(int signum)
{if(0 > signum){fprintf(stderr,"sig_handler param err. [%d]\n",signum);return;}if(SIGINT == signum){printf("Received signal [%s]\n",SIGINT==signum?"SIGINT":"Other");}if(SIGQUIT == signum){printf("Received signal [%s]\n",SIGQUIT==signum?"SIGQUIT":"Other");}return;
}int main(int argc,char **argv)
{printf("Wait for the signal to arrive.\n ");/*登記信息*/signal(SIGINT,sig_handler);signal(SIGQUIT,sig_handler);pause();pause();signal(SIGINT,SIG_IGN);return 0;
}
程序運行后會一直等待用戶的輸入,當在終端按下ctrl+c時候會打印^C Received signal [SIGINT]
說明捕獲到了SIGINT信號,接著程序繼續等待,當按下ctrl+\時候會打印^\Received signal [SIGQUIT]
表明捕獲到了SIGQUIT信號,如下圖所示:
在Linux的目錄/usr/include/x86_64-linux-gnu/bits/signum.h下有對所有信號的宏定義,所以可以用來和int值進行比較。
3. Linux標準信號
在Linux終端下 kill -l 可以查看所有的信號。
這里是上面64種信號的說明:
信號?? ?起源?? ?默認行為?? ?含義
SIGHUP?? ?POSIX?? ?Term?? ?控制終端掛起
SIGINT?? ?ANSI?? ?Term?? ?鍵盤輸入以終端進程(ctrl + C)
SIGQUIT?? ?POSIX?? ?Core?? ?鍵盤輸入使進程退出(Ctrl + \)
SIGILL?? ?ANSI?? ?Core?? ?非法指令
SIGTRAP?? ?POSIX?? ?Core?? ?斷點陷阱,用于調試
SIGABRT?? ?ANSI?? ?Core?? ?進程調用abort函數時生成該信號
SIGIOT?? ?4.2BSD?? ?Core?? ?和SIGABRT相同
SIGBUS?? ?4.2BSD?? ?Core?? ?總線錯誤,錯誤內存訪問
SIGFPE?? ?ANSI?? ?Core?? ?浮點異常
SIGKILL?? ?POSIX?? ?Term?? ?終止一個進程。該信號不可被捕獲或被忽略
SIGUSR1?? ?POSIX?? ?Term?? ?用戶自定義信號之一
SIGSEGV?? ?ANSI?? ?Core?? ?非法內存段使用
SIGUSR2?? ?POSIX?? ?Term?? ?用戶自定義信號二
SIGPIPE?? ?POSIX?? ?Term?? ?往讀端關閉的管道或socket鏈接中寫數據
SIGALRM?? ?POSIX?? ?Term?? ?由alarm或settimer設置的實時鬧鐘超時引起
SIGTERM?? ?ANSI?? ?Term?? ?終止進程。kill命令默認發生的信號就是SIGTERM
SIGSTKFLT?? ?Linux?? ?Term?? ?早期的Linux使用該信號來報告數學協處理器棧錯誤
SIGCLD?? ?System V?? ?Ign?? ?和SIGCHLD相同
SIGCHLD?? ?POSIX?? ?Ign?? ?子進程狀態發生變化(退出或暫停)
SIGCONT?? ?POSIX?? ?Cont?? ?啟動被暫停的進程(Ctrl+Q)。如果目標進程未處于暫停狀態,則信號被忽略
SIGSTOP?? ?POSIX?? ?Stop?? ?暫停進程(Ctrl+S)。該信號不可被捕捉或被忽略
SIGTSTP?? ?POSIX?? ?Stop?? ?掛起進程(Ctrl+Z)
SIGTTIN?? ?POSIX?? ?Stop?? ?后臺進程試圖從終端讀取輸入
SIGTTOU?? ?POSIX?? ?Stop?? ?后臺進程試圖往終端輸出內容
SIGURG?? ?4.3 BSD?? ?Ign?? ?socket連接上接收到緊急數據
SIGXCPU?? ?4.2 BSD?? ?Core?? ?進程的CPU使用時間超過其軟限制
SIGXFSZ?? ?4.2 BSD?? ?Core?? ?文件尺寸超過其軟限制
SIGVTALRM?? ?4.2 BSD?? ?Term?? ?與SIGALRM類似,不過它只統計本進程用戶空間代碼的運行時間
SIGPROF?? ?4.2 BSD?? ?Term?? ?與SIGALRM 類似,它同時統計用戶代碼和內核的運行時間
SIGWINCH?? ?4.3 BSD?? ?Ign?? ?終端窗口大小發生變化
SIGPOLL?? ?System V?? ?Term?? ?與SIGIO類似
SIGIO?? ?4.2 BSD?? ?Term?? ?IO就緒,比如socket上發生可讀、可寫事件。因為TCP服務器可觸發SIGIO的條件很多,故而SIGIO無法在TCP服務器中用。SIGIO信號可用在UDP服務器中,但也很少見
SIGPWR?? ?System V?? ?Term?? ?對于UPS的系統,當電池電量過低時,SIGPWR信號被觸發
SIGSYS?? ?POSIX?? ?Core?? ?非法系統調用
SIGUNUSED?? ??? ?Core?? ?保留,通常和SIGSYS效果相同
?
原文地址:https://blog.csdn.net/lixiaogang_theanswer/article/details/80301624