linux c之信号signal处理机制
最近同事的程序設計過程中用到了Linux的signal機制,從而引發了我對Linux中signal機制的思考。Signal機制在Linux中是一個非常常用的進程間通信機制,很多人在使用的時候不會考慮該機制是具體如何實現的。signal機制可以被理解成進程的軟中斷,因此,在實時性方面還是相對比較高的。Linux中signal機制的模型可以采用下圖進行描述。
個進程都會采用一個進程控制塊對其進行描述,進程控制塊中設計了一個signal的位圖信息,其中的每位與具體的signal相對應,這與中斷機制是保持一致的。當系統中一個進程A通過signal系統調用向進程B發送signal時,設置進程B的對應signal位圖,類似于觸發了signal對應中斷。發送signal只是“中斷”觸發的一個過程,具體執行會在兩個階段發生:
1、? system call返回。進程B由于調用了system call后,從內核返回用戶態時需要檢查他擁有的signal位圖信息表,此時是一個執行點。
2、? 中斷返回。進程被系統中斷打斷之后,系統將CPU交給進程時,需要檢查即將執行進程所擁有的signal位圖信息表,此時也是一個執行點。
?
綜上所述,signal的執行點可以理解成從內核態返回用戶態時,在返回時,如果發現待執行進程存在被觸發的signal,那么在離開內核態之后(也就是將CPU切換到用戶模式),執行用戶進程為該signal綁定的signal處理函數,從這一點上看,signal處理函數是在用戶進程上下文中執行的。當執行完signal處理函數之后,再返回到用戶進程被中斷或者system call(軟中斷或者指令陷阱)打斷的地方。
?
?????? Signal機制實現的比較靈活,用戶進程由于中斷或者system call陷入內核之后,將斷點信息都保存到了堆棧中,在內核返回用戶態時,如果存在被觸發的signal,那么直接將待執行的signal處理函數push到堆棧中,在CPU切換到用戶模式之后,直接pop堆棧就可以執行signal處理函數并且返回到用戶進程了。Signal處理函數應用了進程上下文,并且應用實際的中斷模擬了進程的軟中斷過程。
?
最近寫程序,各種bug各種錯,有一回程序莫名退出,沒報錯,也沒產生日志和core文件,貌似正常退出一樣。
但又不是在程序全部走完后退出,中途莫名退出,這就叫我想到了signal,應該是某些函數錯誤后發送kill信號給主進程,然后退出。
現在總結下signal各種類型:
| Signal | Description |
| SIGABRT | 由調用abort函數產生,進程非正常退出 |
| SIGALRM | 用alarm函數設置的timer超時或setitimer函數設置的interval timer超時 |
| SIGBUS | 某種特定的硬件異常,通常由內存訪問引起 |
| SIGCANCEL | 由Solaris Thread Library內部使用,通常不會使用 |
| SIGCHLD | 進程Terminate或Stop的時候,SIGCHLD會發送給它的父進程。缺省情況下該Signal會被忽略 |
| SIGCONT | 當被stop的進程恢復運行的時候,自動發送 |
| SIGEMT | 和實現相關的硬件異常 |
| SIGFPE | 數學相關的異常,如被0除,浮點溢出,等等 |
| SIGFREEZE | Solaris專用,Hiberate或者Suspended時候發送 |
| SIGHUP | 發送給具有Terminal的Controlling Process,當terminal被disconnect時候發送 |
| SIGILL | 非法指令異常 |
| SIGINFO | BSD signal。由Status Key產生,通常是CTRL+T。發送給所有Foreground Group的進程 |
| SIGINT | 由Interrupt Key產生,通常是CTRL+C或者DELETE。發送給所有ForeGround Group的進程 |
| SIGIO | 異步IO事件 |
| SIGIOT | 實現相關的硬件異常,一般對應SIGABRT |
| SIGKILL | 無法處理和忽略。中止某個進程 |
| SIGLWP | 由Solaris Thread Libray內部使用 |
| SIGPIPE | 在reader中止之后寫Pipe的時候發送 |
| SIGPOLL | 當某個事件發送給Pollable Device的時候發送 |
| SIGPROF | Setitimer指定的Profiling Interval Timer所產生 |
| SIGPWR | 和系統相關。和UPS相關。 |
| SIGQUIT | 輸入Quit Key的時候(CTRL+\)發送給所有Foreground Group的進程 |
| SIGSEGV | 非法內存訪問 |
| SIGSTKFLT | Linux專用,數學協處理器的棧異常 |
| SIGSTOP | 中止進程。無法處理和忽略。 |
| SIGSYS | 非法系統調用 |
| SIGTERM | 請求中止進程,kill命令缺省發送 |
| SIGTHAW | Solaris專用,從Suspend恢復時候發送 |
| SIGTRAP | 實現相關的硬件異常。一般是調試異常 |
| SIGTSTP | Suspend Key,一般是Ctrl+Z。發送給所有Foreground Group的進程 |
| SIGTTIN | 當Background Group的進程嘗試讀取Terminal的時候發送 |
| SIGTTOU | 當Background Group的進程嘗試寫Terminal的時候發送 |
| SIGURG | 當out-of-band data接收的時候可能發送 |
| SIGUSR1 | 用戶自定義signal 1 |
| SIGUSR2 | 用戶自定義signal 2 |
| SIGVTALRM | setitimer函數設置的Virtual Interval Timer超時的時候 |
| SIGWAITING | Solaris Thread Library內部實現專用 |
| SIGWINCH | 當Terminal的窗口大小改變的時候,發送給Foreground Group的所有進程 |
| SIGXCPU | 當CPU時間限制超時的時候 |
| SIGXFSZ | 進程超過文件大小限制 |
| SIGXRES | Solaris專用,進程超過資源限制的時候發送 |
signal對應的值:
POSIX.1中列出的信號:
SIGHUP 1 A 終端掛起或者控制進程終止?
SIGINT 2 A 鍵盤中斷(如break鍵被按下)?
SIGQUIT 3 C 鍵盤的退出鍵被按下?
SIGILL 4 C 非法指令?
SIGABRT 6 C 由abort(3)發出的退出指令?
SIGFPE 8 C 浮點異常?
SIGKILL 9 AEF Kill信號?
SIGSEGV 11 C 無效的內存引用?
SIGPIPE 13 A 管道破裂: 寫一個沒有讀端口的管道?
SIGALRM 14 A 由alarm(2)發出的信號?
SIGTERM 15 A 終止信號?
SIGUSR1 30,10,16 A 用戶自定義信號1?
SIGUSR2 31,12,17 A 用戶自定義信號2?
SIGCHLD 20,17,18 B 子進程結束信號?
SIGCONT 19,18,25 進程繼續(曾被停止的進程)?
SIGSTOP 17,19,23 DEF 終止進程?
SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵?
SIGTTIN 21,21,26 D 后臺進程企圖從控制終端讀?
SIGTTOU 22,22,27 D 后臺進程企圖從控制終端寫?
沒在POSIX.1中列出,而在SUSv2列出
SIGBUS 10,7,10 C 總線錯誤(錯誤的內存訪問)?
SIGPOLL A Sys V定義的Pollable事件,與SIGIO同義?
SIGPROF 27,27,29 A Profiling定時器到?
SIGSYS 12,-,12 C 無效的系統調用 (SVID)?
SIGTRAP 5 C 跟蹤/斷點捕獲?
SIGURG 16,23,21 B Socket出現緊急條件(4.2 BSD)?
SIGVTALRM 26,26,28 A 實際時間報警時鐘信號(4.2 BSD)?
SIGXCPU 24,24,30 C 超出設定的CPU時間限制(4.2 BSD)?
SIGXFSZ 25,25,31 C 超出設定的文件大小限制(4.2 BSD)?
(對于SIGSYS,SIGXCPU,SIGXFSZ,以及某些機器體系結構下的SIGBUS,Linux缺省的動作是A (terminate),SUSv2 是C (terminate and dump core))。?
下面是其它的一些信號?信號 值 處理動作 發出信號的原因?
----------------------------------------------------------------------?
SIGIOT 6 C IO捕獲指令,與SIGABRT同義?
SIGEMT 7,-,7?
SIGSTKFLT -,16,- A 協處理器堆棧錯誤?
SIGIO 23,29,22 A 某I/O操作現在可以進行了(4.2 BSD)?
SIGCLD -,-,18 A 與SIGCHLD同義?
SIGPWR 29,30,19 A 電源故障(System V)?
SIGINFO 29,-,- A 與SIGPWR同義?
SIGLOST -,-,- A 文件鎖丟失?
SIGWINCH 28,28,20 B 窗口大小改變(4.3 BSD, Sun)?
SIGUNUSED -,31,- A 未使用的信號(will be SIGSYS)?
(在這里,- 表示信號沒有實現;有三個值給出的含義為,第一個值通常在Alpha和Sparc上有效,中間的值對應i386和ppc以及sh,最后一個值對應mips。信號29在Alpha上為SIGINFO / SIGPWR ,在Sparc上為SIGLOST。)?
處理動作一項中的字母含義如下?
A 缺省的動作是終止進程?
B 缺省的動作是忽略此信號?
C 缺省的動作是終止進程并進行內核映像轉儲(dump core)?
D 缺省的動作是停止進程?
E 信號不能被捕獲?
F 信號不能被忽略
代碼測試
#include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h> void when_alarm(); void when_sigint(); void when_sigchld(int); void when_sigusr1(); void when_sigio(); int main() { int childpid;//子程序進程ID號 printf("程序已經開始運行,5秒鐘后將接收到時鐘信號。/n"); if ((childpid=fork())>0)//父進程 { signal(SIGALRM,when_alarm); //當接收到SIGALRM信號時,調用when_alarm函數 signal(SIGINT,when_sigint); //當接收到SIGINT信號時,調用when_sigint函數 signal(SIGCHLD,when_sigchld);//當接收到SIGCHLD信號時,調用when_sigchld函數 signal(SIGUSR1,when_sigusr1);//當接收到SIGUSR1信號時,調用when_sigusr1函數 signal(SIGIO,when_sigio);//當接收到SIGIO信號時,調用when_sigio函數 alarm(5); //5秒鐘之后產生SIGALRM信號 raise(SIGIO); //向自己發送一個SIGIO信號 pause(); //將父進程暫停下來,等待SIGALRM信號到來 pause(); //將父進程暫停下來,等待SIGUSR1信號到來 pause(); //將父進程暫停下來,等待SIGCHLD信號到來 printf("------此時程序會停下來等待,請按下ctrl+c送出SIGINT信號-------/n"); pause(); //將父進程暫停下來,等待SIGINT信號到來 } else if(childpid==0) //子進程 { int timer; for(timer=7;timer>=0;timer--) //時鐘計時5秒產生SIGALRM信號,再過2秒子進程退出,產生SIGCHLD信號 { if(timer>2) printf("距離SIGALRM信號到來還有%d秒。/n",timer-2); if(timer==4) kill(getppid(),SIGUSR1); //向父進程發送一個SIGUSR1信號 if((timer<=2)&&(timer>0)) printf("子進程還剩%d秒退出,屆時會產生SIGCHLD信號。/n",timer); if(timer==0) //子進程退出,產生SIGCHLD信號 raise(SIGKILL); //子進程給自己發一個結束信號 sleep(1); //每個循環延時1秒鐘 } } else printf("fork()函數調用出現錯誤!/n"); return 0; } void when_alarm() { printf("5秒鐘時間已到,系統接收到了SIGALRM信號!/n"); } void when_sigint() { printf("已經接收到了SIGINT信號,程序將退出!/n"); exit(0); } void when_sigchld(int SIGCHLD_num) { printf("收到SIGCHLD信號,表明我的子進程已經中止,SIGCHLD信號的數值是:%d。/n",SIGCHLD_num); } void when_sigusr1() { printf("系統接收到了用戶自定義信號SIGUSR1。/n"); } void when_sigio() { printf("系統接收到了SIGIO信號。/n"); }
總結
以上是生活随笔為你收集整理的linux c之信号signal处理机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux之内核剖析
- 下一篇: linux之od命令总结