中斷是系統對於異步事件的響應, 進程執行代碼的過程中可以隨時被打斷,然後去執行異常處理程序;
計算機系統的中斷場景:中斷源發出中斷信號 -> CPU判斷中斷是否屏蔽以及保護現場 -> CPU(查詢中斷向量表, 找到中斷服務程序的入口地址)執行中斷處理程序 ->(處理完中斷之後) ->恢復現場,繼續執行原來的任務
中斷分類
硬件中斷(外部中斷)
外部中斷是指由外部設備通過硬件請求的方式產生的中斷,也稱為硬件中斷
軟件中斷(內部中斷)
內部中斷是由CPU運行程序錯誤或執行內部程序調用引起的一種中斷,也稱為軟件中斷(如:執行除0操作, 由用戶空間陷入內核空間等)。
信號是UNIX/Linux系統響應某些狀況而產生的事件,進程在接收到信號時會采取相應的行動。信號一般是因為某些錯誤條件而產生的,比如內存段沖突、浮點處理器錯誤或者非法指令等;信號是在軟件層次上對中斷的一種模擬,所以通常把它稱為是軟中斷;
信號與中斷的相似點:
(1)采用了相同的異步通信方式;
(2)當檢測出有信號或中斷請求時,都暫停正在執行的程序而轉去執行相應的處理程序;
(3)都在處理完畢後返回到原來的斷點;
(4)對信號或中斷都可進行屏蔽。
信號與中斷的區別:
(1)中斷有優先級,而信號沒有優先級,所有的信號都是平等的;
(2)信號處理程序是在用戶態下運行的,而中斷處理程序是在核心態下運行;
(3)中斷響應是及時的,而信號響應通常都有較大的時間延遲。
Linux常用信號及其鍵值:
01 SIGHUP 掛起(hangup)
02 SIGINT 中斷,當用戶從鍵盤按^c鍵或^break鍵時
03 SIGQUIT 退出,當用戶從鍵盤按quit鍵時
04 SIGILL 非法指令
05 SIGTRAP 跟蹤陷阱(trace trap),啟動進程,跟蹤代碼的執行
06 SIGIOT IOT指令
07 SIGEMT EMT指令
08 SIGFPE 浮點運算溢出
09 SIGKILL 殺死、終止進程
10 SIGBUS 總線錯誤
11 SIGSEGV 段違例(segmentation violation),進程試圖去訪問其虛地址空間以外的位置
12 SIGSYS 系統調用中參數錯,如系統調用號非法
13 SIGPIPE 向某個非讀管道中寫入數據
14 SIGALRM 鬧鐘。當某進程希望在某時間後接收信號時發此信號
15 SIGTERM 軟件終止(software termination)
16 SIGUSR1 用戶自定義信號1
17 SIGUSR2 用戶自定義信號2
18 SIGCLD 某個子進程死
19 SIGPWR 電源故障
更加詳細的請參考 http://www.chengxuyuans.com/Linux/65677.html
進程對信號的響應可以分為一下幾種情況:
(1)忽略信號
不采取任何操作、有兩個信號不能被忽略:SIGKILL和SIGSTOP。
[為什麼進程不能忽略SIGKILL/SIGSTOP信號。(如果應用程序可以忽略這2個信號,系統管理無法殺死、暫停進程,無法對系統進行管理。)]
(2)捕獲並處理信號
內核中斷正在執行的代碼,轉去執行先前注冊過的處理程序。
(3)執行默認操作
默認操作通常是終止進程,這取決於被發送的信號。
信號的默認操作:通過 man 7 signal 查看
typedef void (*__sighandler_t) (int); #define SIG_ERR ((__sighandler_t) -1) #define SIG_DFL ((__sighandler_t) 0) #define SIG_IGN ((__sighandler_t) 1) __sighandler_t signal(int signum, __sighandler_t handler);
參數
signal是一個帶signum和handler兩個參數的函數,准備捕捉或屏蔽的信號由參數signum給出,接收到指定信號時將要調用的函數由handler給出handler這個函數必須有一個int類型的參數(即接收到的信號代碼),它本身的類型是void, handler也可以是下面兩個特殊值:
SIG_IGN 屏蔽該信號
SIG_DFL 恢復默認行為
並且返回的是上一次的信號處理函數,第一次的話則返回的是默認的處理函數。
void handler(int sig) { printf("recv a sig=%d\n",sig); } int main() { sig_t oldhandler; oldhandler=signal(SIGINT,handler); if(oldhandler==SIG_ERR) ERR_EXIT("signal error!"); while(getchar()!='\n'); if(signal(SIGINT,oldhandler)==SIG_ERR)// fanhuishangyicide signal ERR_EXIT("signal error!"); while(1); return 0; }
我們分析一下以上程序的結果:我們先樹勇signal注冊了一個SIGINT信號,每次使用ctrl+c時發出信號,執行handler函數,注意handler一定要有一個int形參。輸入回車跳出while循環,再次輸入ctrl+c時,這時候的handler是oldhandler(默認)所以會退出。