1. 程式人生 > 其它 >20191320-2021-2022-1-diocs 學習筆記9

20191320-2021-2022-1-diocs 學習筆記9

第6章 訊號和訊號處理

6.1~6.3 訊號和中斷

中斷:中斷是I/O裝置傳送到CPU的外部請求,將CPU從正常執行轉移到中斷處理。
訊號:訊號是傳送給程序的請求,將程序從正常執行轉移到中斷處理。
中斷的型別:

  1. 人員中斷
  2. 程序中斷
  3. 硬體中斷
  4. 程序的陷阱錯誤

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