20191320-2021-2022-1-diocs 學習筆記9
阿新 • • 發佈:2021-11-13
第6章 訊號和訊號處理
6.1~6.3 訊號和中斷
中斷:中斷是I/O裝置傳送到CPU的外部請求,將CPU從正常執行轉移到中斷處理。
訊號:訊號是傳送給程序的請求,將程序從正常執行轉移到中斷處理。
中斷的型別:
- 人員中斷
- 程序中斷
- 硬體中斷
- 程序的陷阱錯誤
Unix/Linux支援31種不同的訊號,每種訊號在signal.h檔案中都有定義。
#define SIGHUP 1 #define SIGINT 2 #define SIGQUIT 3 #define SIGILL 4 #define SIGTRAP 5 #define SIGABRT 6 #define SIGIOT 6 #define SIGBUS 7 #define SIGFPE 8 #define SIGKILL 9 #define SIGUSR1 10 #define SIGSEGV 11 #define SIGUSR2 12 #define SIGPIPE 13 #define SIGALRM 14 #define SIGTERM 15 #define SIGSTKFLT 16 #define SIGCHLD 17 #define SIGCONT 18 #define SIGSTOP 19 #define SIGTSTP 20 #dpfine STGTTTN 21 #define SIGTTOU 22 #define SIGURG 23 #define SIGXCPU 24 #define SIGXFSZ 25 #define SIGVTALRM 26 #define SIGPROF 27 #define SIGWINCH 28 #define SIGPOLL 29 #define SIGPWR 30 #define SIGSYS 31
這些訊號的不同來源有:
- 來自硬體的中斷訊號
- 來自異常的訊號
- 來自其他程序的訊號
6.4~6.7 訊號處理步驟、IPC
在許多作業系統的書籍中,訊號被歸類為程序間的通訊機制。基本原理是一個程序可以向另一個程序傳送訊號,使它執行預先安裝的訊號處理函式。
- 該機制並不可靠,因為可能會丟失訊號。每個訊號由位向量中的一個位表示,只能記 錄一個訊號的一次岀現.如果某個程序向另一個程序傳送兩個或多個相同的訊號,它 們可能只在接收PROC中出現一次。實時訊號被放入佇列,並保證按接收順序傳送, 但作業系統核心可能不支援實時訊號。
- 競態條件:在處理訊號之前,程序通常會將訊號處理函式重置為DEFault。要想捕捉同一訊號的再次出現,程序必須在該訊號再次到來之前重新安裝捕捉函式。否則,下 一個訊號可能會導致該程序終止。在執行訊號捕捉函式時,雖然可以通過阻塞同一信 號來防止競態條件,但是無法防止丟失訊號。
- 大多數訊號都有預定義的含義。不加區別地任意使用訊號不僅不能達到通訊的目的,反而會造成混亂。例如,向迴圈程序傳送SIGSEGV(11)段錯誤訊號,出現錯誤的資訊。
因此,試圖將訊號用作程序間通訊手段實際上是對訊號預期用途的過度延伸.應避免出現這種情況。
實踐內容過程、問題解決過程
按照書上的程式碼進行了實踐,如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <setjmp.h> #include <string.h> jmp_buf env; int count = 0; void handler(int sig, siginfo_t *siginfo, void *context) { printf("handler: sig=%d from PID=%d UID=%d count=%d\n", sig, siginfo->si_pid, siginfo->si_uid, ++count); if (count >= 4) // let it occur up to 4 times longjmp(env, 1234); } int BAD() { int *ip = 0; printf("in BAD(): try to dereference NULL pointer\n"); *ip = 123; // dereference a NULL pointer printf("should not see this line\n"); } int main(int argc, char *argv[]) { int r; struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_sigaction = &handler; act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, NULL); if ((r = setjmp(env)) == 0) BAD(); else printf("proc %d survived SEGMENTATION FAULT: r=%d\n", getpid(), r); printf("proc %d looping\n", getpid()); while (1) ; }
實踐截圖:
程式碼連結
程式碼包括一些以前的程式碼,在碼雲。連結:https://gitee.com/Ressurection20191320/code/tree/master/IS