1. 程式人生 > 其它 >springboot整合websocket中自動注入null問題

springboot整合websocket中自動注入null問題

◼ 訊號是 Linux 程序間通訊的最古老的方式之一,是事件發生時對程序的通知機制,有時也稱之為軟體中斷,它是在軟體層次上對中斷機制的一種模擬,是一種非同步通訊的方式。訊號可以導致一個正在執行的程序被另一個正在執行的非同步程序中斷,轉而處理某一個突發事件。

 對於前臺程序,使用者可以通過輸入特殊的終端字元來給它傳送訊號。比如輸入Ctrl+C通常會給程序傳送一箇中斷訊號。
 硬體發生異常,即硬體檢測到一個錯誤條件並通知核心,隨即再由核心傳送相應訊號給相關程序。比如執行一條異常的機器語言指令,諸如被 0 除,或者引用了無法訪問的記憶體區域。
 系統狀態變化,比如 alarm 定時器到期將引起 SIGALRM 訊號,程序執行的 CPU時間超限,或者該程序的某個子程序退出。
 執行 kill 命令或呼叫 kill 函式。

◼ 使用訊號的兩個主要目的是:
 讓程序知道已經發生了一個特定的事情。
 強迫程序執行它自己程式碼中的訊號處理程式。
◼ 訊號的特點:
 簡單
 不能攜帶大量資訊
 滿足某個特定條件才傳送
 優先順序比較高
◼ 檢視系統定義的訊號列表:kill –l
◼ 前 31 個訊號為常規訊號,其餘為實時訊號。

setitimer和alarm

alarm和setitimer(ITIMER_PROF) 共享同一個定時器。即alarm的定時時間包含的是:使用者+系統核心的執行時間

alarm定一次時,setitimer週期性定時

signal訊號捕捉

要捕捉訊號在之前就註冊訊號捕捉

#include <sys/time.h>
#include 
<stdio.h> #include <stdlib.h> #include <signal.h> void myalarm(int num) { printf("捕捉到了訊號的編號是:%d\n", num); printf("xxxxxxx\n"); } // 過3秒以後,每隔2秒鐘定時一次 int main() { // 註冊訊號捕捉 // signal(SIGALRM, SIG_IGN); // signal(SIGALRM, SIG_DFL); // void (*sighandler_t)(int); 函式指標,int型別的引數表示捕捉到的訊號的值。
signal(SIGALRM, myalarm); struct itimerval new_value; // 設定間隔的時間 new_value.it_interval.tv_sec = 2; new_value.it_interval.tv_usec = 0; // 設定延遲的時間,3秒之後開始第一次定時 new_value.it_value.tv_sec = 3; new_value.it_value.tv_usec = 0; int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的 printf("定時器開始了...\n"); if(ret == -1) { perror("setitimer"); exit(0); } getchar(); return 0; }

訊號集

PCB中有兩個非常重要的訊號集,1.“阻塞訊號集”2.未決訊號集“ 這連個訊號集都是核心使用點陣圖機制實現的

64位的整數,每一位表示一種訊號,每一位0或者1(各表示一種情況) 作業系統不允許我們直接對兩個訊號進行位操作 需自定義另外一個集合,藉助訊號集操作函式來對PCB中的兩個訊號集進行修改

未決訊號集 無法直接去修改 未決 指的是 從訊號的產生到被處理前的這段時間

阻塞是一個開關動作,指的是阻止訊號被處理


/*
1
.使用者通過鍵盤 Ctrl + C, 產生2號訊號SIGINT (訊號被建立) 2.訊號產生但是沒有被處理 (未決) - 在核心中將所有的沒有被處理的訊號儲存在一個集合中 (未決訊號集) - SIGINT訊號狀態被儲存在第二個標誌位上 - 這個標誌位的值為0, 說明訊號不是未決狀態 - 這個標誌位的值為1, 說明訊號處於未決狀態 3.這個未決狀態的訊號,需要被處理,處理之前需要和另一個訊號集(阻塞訊號集),進行比較 - 阻塞訊號集預設不阻塞任何的訊號 - 如果想要阻塞某些訊號需要使用者呼叫系統的API 4.在處理的時候和阻塞訊號集中的標誌位進行查詢,看是不是對該訊號設定阻塞了 - 如果沒有阻塞,這個訊號就被處理 - 如果阻塞了,這個訊號就繼續處於未決狀態,直到阻塞解除,這個訊號就被處理
*/

對核心的訊號集進行修改

sigpromask() 設定阻塞訊號集

/*
    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
        - 功能:將自定義訊號集中的資料設定到核心中(設定阻塞,解除阻塞,替換)
        - 引數:
            - how : 如何對核心阻塞訊號集進行處理
                SIG_BLOCK: 將使用者設定的阻塞訊號集新增到核心中,核心中原來的資料不變
                    假設核心中預設的阻塞訊號集是mask, mask | set
                SIG_UNBLOCK: 根據使用者設定的資料,對核心中的資料進行解除阻塞
                    mask &= ~set
                SIG_SETMASK:覆蓋核心中原來的值
            
            - set :已經初始化好的使用者自定義的訊號集
            - oldset : 儲存設定之前的核心中的阻塞訊號集的狀態,可以是 NULL
        - 返回值:
            成功:0
            失敗:-1
                設定錯誤號:EFAULT、EINVAL

    int sigpending(sigset_t *set);
        - 功能:獲取核心中的未決訊號集
        - 引數:set,傳出引數,儲存的是核心中的未決訊號集中的資訊。
*/

sigaction()訊號捕捉函式

儘量使用sigaction()函式而不是signal函式

/*
    #include <signal.h>
    int sigaction(int signum, const struct sigaction *act,
                            struct sigaction *oldact);

        - 功能:檢查或者改變訊號的處理。訊號捕捉
        - 引數:
            - signum : 需要捕捉的訊號的編號或者巨集值(訊號的名稱)
            - act :捕捉到訊號之後的處理動作
            - oldact : 上一次對訊號捕捉相關的設定,一般不使用,傳遞NULL
        - 返回值:
            成功 0
            失敗 -1

     struct sigaction {
        // 函式指標,指向的函式就是訊號捕捉到之後的處理函式
        void     (*sa_handler)(int);
        // 不常用
        void     (*sa_sigaction)(int, siginfo_t *, void *);
        // 臨時阻塞訊號集,在訊號捕捉函式執行過程中,臨時阻塞某些訊號。
        sigset_t   sa_mask;
        // 使用哪一個訊號處理對捕捉到的訊號進行處理
        // 這個值可以是0,表示使用sa_handler,也可以是SA_SIGINFO表示使用sa_sigaction
        int        sa_flags;
        // 被廢棄掉了
        void     (*sa_restorer)(void);
    };

*/
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myalarm(int num) {
    printf("捕捉到了訊號的編號是:%d\n", num);
    printf("xxxxxxx\n");
}

// 過3秒以後,每隔2秒鐘定時一次
int main() {

    struct sigaction act;
    act.sa_flags = 0;
    act.sa_handler = myalarm;
    sigemptyset(&act.sa_mask);  // 清空臨時阻塞訊號集
   
    // 註冊訊號捕捉
    sigaction(SIGALRM, &act, NULL);

    struct itimerval new_value;

    // 設定間隔的時間
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 設定延遲的時間,3秒之後開始第一次定時
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定時器開始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    getchar();
    // while(1);

    return 0;
}

注意:一開始核心中存在一個阻塞訊號集,在訊號捕捉處理的過程中,會使用臨時的阻塞訊號集,當訊號處理完成後,會恢復到pcb內部的阻塞訊號集。

2.在執行某個回撥函式期間,比如說捕捉sigalarm訊號,此時SIGALARM訊號預設被遮蔽掉,不管再去發SIGALARM訊號,都不去執行回撥函式,等前一次的回撥函式執行後,才會繼續執行

3.阻塞的常規訊號是不支援排隊的,未決訊號集和阻塞訊號集都是通過標誌位控制,因此只能記錄0或1