‘信號’基本概念總結

      生活中有許許多多的信號,能夠反映給人類,人類能夠產生相應的行爲。當我們使用鍵盤給計算機一個信號,計算機也會相應的產生一系列的行爲。在linux系統中,使用kill -l命令能夠查看系統中所有的信號如下:


wKioL1eXWkjAIKI3AACLfuXkW8I273.png

      其中:系統中總共有62中信號,前31種信號稱爲普通信號,後31中稱爲實時信號。當然在這裏主要討論的是前31種。


★信號產生

(1)信號產生的方式主要有以下4種:

         ①鍵盤:當一個進程正在運行時,可以從鍵盤上輸入ctrl+c使得進程終止,其實是鍵盤上輸入的信息被系統捕捉,系統向前臺進程發送2號信號(即就是SIGINT),進而將程序進行終止。

         注:信號反映於前臺,後臺沒有作用,不能使得程序終止。向後臺反映使用&,如:./test &

 

例:

wKioL1eXXtfgkAyVAAAoIPztGB8517.png

運行結果:

wKioL1eXXpngLKcnAAAXOFQpfv0104.png


           ②命令:可以使用kill  [信號]  PID  這個命令。如:kill -2 10236


           ③函數:可以使用raise( )函數和abort( )函數。

                    int kill(pid_t pid, int signo);

                       int raise(int signo);

                       void abort(void);


          ④軟件條件:利用alarm函數,設置鬧鐘,等到一定時間後,向當前進程發送SIGALRM信號。


例:

wKioL1eXZL7AIBK4AAA6czADqAk198.png

運行結果:

wKiom1eXZITxqT1QAAAUXd_3Uco071.png



★信號處理

(1)進程的處理方式有3種:

           ①忽略此信號

           ②執行默認的處理方式

           ③提供自定義的信號處理函數,將其稱爲捕捉


     注:①絕大部分進程接收到信號不會立即進行處理的,會先將其保存在自己的PCB中,等到合適的時候進行處理。

            ②信號的默認處理方式是終止進程。


(2)相關概念:

           信號未決:將信號產生到信號執行之前這段時間稱爲信號未決。

           阻塞:進程可以阻塞某個信號,被阻塞後的信號只有解除阻塞,才能夠進行執行。

           信號遞達:將信號的處理動作稱爲遞達。


     注:信號的產生和阻塞是沒有關係的,所以即使沒有產生信號,系統也可以將此種信號進行阻塞。


wKiom1eXba3RW6e6AAAcVEhZ-28997.png

      在linux系統中,只記錄產生了哪種信號,並不會將信號的次數進行記錄,所以只需要將31種信號用4個字節(32)位來進行表示,這些信息都會保存在進程的PCB中,存在block、pending、handler。block表示每個信號是否被阻塞,0表示沒有阻塞,1表示被阻塞。pending表示進程中是否存在某種信號,0表示不存在,1表示存在,。handler表示存儲方式,SIG_DFL表示執行默認的處理方式,SIG_IGN表示忽略此信號。

      未決和阻塞都可以使用相同的數據類型sigset_t來存儲,可以表示有效、無效兩種狀態,分別稱爲‘信號屏蔽字’和‘pending信號集’。

      注:信號集中不能使用位運算來進行操作。


★信號集操作函數

       頭文件:#include <signal.h>

        函數:int sigemptyset(sigset_t* set);               //將信號集中所有的數據置爲無效

                     int sigfillset(sigset_t* set);                      //將信號集中所有的數據置爲有效

                     int sigaddset(sigset_t* set, int signo);    //在信號集中增加哪個信號

                     int sigdelset(sigset_t* set, int signo);     //刪除信號集中的某個信號

                     int sigismember(const sigset_t* set, int signo);    //判斷某個信號是否在信號集中

        int sigprocmask(int how, const sigset_t* set, sigset_t* oset);   //獲取或更改進程的信號屏蔽字

        int sigpending(sigset_t* set);         //獲取當前進程的未決信號集


例:

wKioL1eYb4Dg-A5BAACMXrzs_B4384.png

運行結果:

wKiom1eYcOXzUdzxAAAVQ2sKRkE794.png


★捕捉信號

     在上面提到信號產生後,進程不是立即對其處理,而是先將其保存在自己的PCB中,等到合適的時候來處理。其實,合適的時候就是:在由於某些異常原因,進程從用戶態切換到內核態,返回之前需要對信號進行檢查、處理(即就是內核態到用戶態切換時)。


     int sigaction(int signo, const struct sigaction* act, struct sigaction* oact);   //讀取和修改指定信號的處理動作。

     int pause(void);     //將進程掛起,直到有信號遞達


例:使用上面兩個函數完成sleep函數


wKioL1eYe-DycY4VAADE3DGC-0E849.png

運行結果:

wKioL1eYetLhpnihAAAVkkG6ssc154.png


      注:這裏不考慮多線程的切換問題。




本文出自 “無心的執着” 博客,謝絕轉載!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章