1. 程式人生 > >ubuntu 訊號:Signal

ubuntu 訊號:Signal

一、訊號概念 

訊號是程序在執行過程中,由自身產生或由程序外部發過來的訊息(事件)。訊號是硬體中斷的軟體模擬(軟中斷)。每個訊號用一個整型常量巨集表示,以SIG開頭,比如SIGCHLD、SIGINT等,它們在系統標頭檔案中定義,也可以通過在shell下鍵入kill –l檢視訊號列表,或者鍵入man 7 signal檢視更詳細的說明。

訊號的生成來自核心,讓核心生成訊號的請求來自3個地方:

  1. 使用者:使用者能夠通過輸入CTRL+c、Ctrl+,或者是終端驅動程式分配給訊號控制字元的其他任何鍵來請求核心產生訊號;
  2. 核心:當程序執行出錯時,核心會給程序傳送一個訊號,例如非法段存取(記憶體訪問違規)、浮點數溢位等;
  3. 程序:一個程序可以通過系統呼叫kill給另一個程序傳送訊號,一個程序可以通過訊號和另外一個程序進行通訊。

由程序的某個操作產生的訊號稱為同步訊號(synchronous signals),例如除0;由象使用者擊鍵這樣的程序外部事件產生的訊號叫做非同步訊號。(asynchronous signals)。
程序接收到訊號以後,可以有如下3種選擇進行處理:

  1. 接收預設處理:接收預設處理的程序通常會導致程序本身消亡。例如連線到終端的程序,使用者按下CTRL+c,將導致核心向程序傳送一個SIGINT的訊號,程序如果不對該訊號做特殊的處理,系統將採用預設的方式處理該訊號,即終止程序的執行;
  2. 忽略訊號:程序可以通過程式碼,顯示地忽略某個訊號的處理,例如:signal(SIGINT,SIGDEF);但是某些訊號是不能被忽略的,
  3. 捕捉訊號並處理:程序可以事先註冊訊號處理函式,當接收到訊號時,由訊號處理函式自動捕捉並且處理訊號。

 
有兩個訊號既不能被忽略也不能被捕捉,它們是SIGKILL和SIGSTOP。即程序接收到這兩個訊號後,只能接受系統的預設處理,即終止執行緒。

二、Signal ()函式詳細介紹

1. 功能

設定某一訊號的對應動作

2. 宣告

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

3. 引數說明 

第一個引數signum:指明瞭所要處理的訊號型別,它可以取除了SIGKILL和SIGSTOP外的任何一種訊號。   
第二個引數handler:描述了與訊號關聯的動作,它可以取以下三種值: 

(1)SIG_IGN   這個符號表示忽略該訊號。 

例如:

#include <stdio.h>
#include <signal.h>
int main(int argc, char *argv[]) {
    signal(SIGINT, SIG_IGN);
    while(1);
    return 0;
}

SIGINT訊號代表由InterruptKey產生,通常是CTRL +C 或者是DELETE 。執行上述程式碼時,按下CTRL + C程式沒有反應。這就對了,如果我們想結束該程式可以按下CTRL +\來結束,當我們按下CTRL +\組合鍵時,產生了SIGQUIT訊號,此訊號並沒有被忽略。
(2)SIG_DFL   這個符號表示恢復對訊號的系統預設處理。不寫此處理函式預設也是執行系統預設操作。 
例如:

#include <stdio.h>
#include <signal.h>
int main(int argc, char *argv[]) {
    signal(SIGINT, SIG_DFL);
    while(1);
    return 0;
}

這個符號表示恢復對訊號的系統預設處理。不寫此處理函式預設也是執行系統預設操作。 

(3)sighandler_t型別的函式指標    上面提到了sighandler_t型別宣告:

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

此函式必須在signal()被呼叫前申明,handler中為這個函式的名字。當接收到一個型別為sig的訊號時,就執行handler 所指定的函式。(int)signum是傳遞給它的唯一引數。執行了signal()呼叫後,程序只要接收到型別為sig的訊號,不管其正在執行程式的哪一部分,就立即執行func()函式。當func()函式執行結束後,控制權返回程序被中斷的那一點繼續執行。 
例如:

#include <stdio.h>
#include <signal.h>
typedef void (*signal_handler)(int);

void signal_handler_fun(int signum) {
    printf("catch signal %d\n", signum);
}

int main(int argc, char *argv[]) {
    signal(SIGINT, signal_hander_fun);
    while(1);
    return 0;
}

執行時,當我們按下CTRL +C鍵時,會執行我們定義的訊號處理函式。

catch signal 2
=退出

每當我們按下CTRL +C鍵時會列印該訊號的number.可以看出該訊號的num為2。要想退出可以按下CTRL +\ 列印結果為最後一行。

4. 函式說明 

  • signal()會依引數signum 指定的訊號編號來設定該訊號的處理函式。
  • 當指定的訊號到達時就會跳轉到引數handler指定的函式執行。

當一個訊號的訊號處理函式執行時,如果程序又接收到了該訊號,該訊號會自動被儲存而不會中斷訊號處理函式的執行,直到訊號處理函式執行完畢再重新呼叫相應的處理函式。但是如果在訊號處理函式執行時程序收到了其它型別的訊號,該函式的執行就會被中斷。

5. 返回值

返回先前的訊號處理函式指標,如果有錯誤則返回SIG_ERR(-1)。   

6. 一些常用的Signal :

  1. Signal    Description
  2. SIGABRT    由呼叫abort函式產生,程序非正常退出
  3. SIGALRM    用alarm函式設定的timer超時或setitimer函式設定的interval timer超時
  4. SIGBUS    某種特定的硬體異常,通常由記憶體訪問引起
  5. SIGCANCEL    由Solaris Thread Library內部使用,通常不會使用
  6. SIGCHLD    程序Terminate或Stop的時候,SIGCHLD會發送給它的父程序。預設情況下該Signal會被忽略
  7. SIGCONT    當被stop的程序恢復執行的時候,自動傳送
  8. SIGEMT    和實現相關的硬體異常
  9. SIGFPE    數學相關的異常,如被0除,浮點溢位,等等
  10. SIGFREEZE    Solaris專用,Hiberate或者Suspended時候傳送
  11. SIGHUP    傳送給具有Terminal的Controlling Process,當terminal 被disconnect時候傳送
  12. SIGILL    非法指令異常
  13. SIGINFO    BSD signal。由Status Key產生,通常是CTRL+T。傳送給所有Foreground Group的程序
  14. SIGINT    由Interrupt Key產生,通常是CTRL+C或者DELETE。傳送給所有ForeGround Group的程序
  15. SIGIO    非同步IO事件
  16. SIGIOT    實現相關的硬體異常,一般對應SIGABRT
  17. SIGKILL    無法處理和忽略。中止某個程序
  18. SIGLWP    由Solaris Thread Libray內部使用
  19. SIGPIPE    在reader中止之後寫Pipe的時候傳送
  20. SIGPOLL    當某個事件傳送給Pollable Device的時候傳送
  21. SIGPROF    Setitimer指定的Profiling Interval Timer所產生
  22. SIGPWR    和系統相關。和UPS相關。
  23. SIGQUIT    輸入Quit Key的時候(CTRL+\)傳送給所有Foreground Group的程序
  24. SIGSEGV    非法記憶體訪問
  25. SIGSTKFLT    Linux專用,數學協處理器的棧異常
  26. SIGSTOP    中止程序。無法處理和忽略。
  27. SIGSYS    非法系統呼叫
  28. SIGTERM    請求中止程序,kill命令預設傳送
  29. SIGTHAW    Solaris專用,從Suspend恢復時候傳送
  30. SIGTRAP    實現相關的硬體異常。一般是除錯異常
  31. SIGTSTP    Suspend Key,一般是Ctrl+Z。傳送給所有Foreground Group的程序
  32. SIGTTIN    當Background Group的程序嘗試讀取Terminal的時候傳送
  33. SIGTTOU    當Background Group的程序嘗試寫Terminal的時候傳送
  34. SIGURG    當out-of-band data接收的時候可能傳送
  35. SIGUSR1    使用者自定義signal 1
  36. SIGUSR2    使用者自定義signal 2
  37. SIGVTALRM    setitimer函式設定的Virtual Interval Timer超時的時候
  38. SIGWAITING    Solaris Thread Library內部實現專用
  39. SIGWINCH    當Terminal的視窗大小改變的時候,傳送給Foreground Group的所有程序
  40. SIGXCPU    當CPU時間限制超時的時候
  41. SIGXFSZ    程序超過檔案大小限制
  42. SIGXRES    Solaris專用,程序超過資源限制的時候發