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