深入理解處理序間通訊之訊號,深入理解進程通訊
訊號及訊號源
訊號本質
訊號是在軟體層次上對中斷機制的一種類比,在原理上,一個進程收到一個訊號與處理器收到一個插斷要求可以說是一樣的。訊號是非同步,一個進程不必通過任何操作來等待訊號的到達,事實上,進程也不知道訊號到底什麼時候到達。
訊號是處理序間通訊機制中唯一的非同步通訊機制,可以看作是非同步通知,通知接收訊號的進程有哪些事情發生了。訊號機制經過POSIX即時擴充後,功能更加強大,除了基本通知功能外,還可以傳遞附加資訊。
訊號來源
訊號事件的發生有兩個來源:硬體來源(比如我們按下了鍵盤或者其它硬體故障);軟體來源,最常用發送訊號的系統函數是kill, raise, alarm和setitimer以及sigqueue函數,軟體來源還包括一些非法運算等操作。
進程對訊號的響應
進程可以通過三種方式來響應一個訊號:(1)忽略訊號,即對訊號不做任何處理,其中,有兩個訊號不能忽略:SIGKILL及SIGSTOP;(2)捕捉訊號。定義訊號處理函數,當訊號發生時,執行相應的處理函數;(3)執行預設操作,Linux對每種訊號都規定了預設操作。注意,進程對即時訊號的預設反應是進程終止。
Linux究竟採用上述三種方式的哪一個來響應訊號,取決於傳遞給相應API函數的參數。
訊號的安裝
如果進程要處理某一訊號,那麼就要在進程中安裝該訊號。安裝訊號主要用來確定訊號值及進程針對該訊號值的動作之間的映射關係,即進程將要處理哪個訊號;該訊號被傳遞給進程時,將執行何種操作。
Linux主要有兩個函數實現訊號的安裝:signal()、sigaction()。其中signal()在可靠訊號系統調用的基礎上實現, 是庫函數。它只有兩個參數,不支援訊號傳遞資訊,主要是用於前32種非即時訊號的安裝;而sigaction()是較新的函數(由兩個系統調用實現:sys_signal以及sys_rt_sigaction),有三個參數,支援訊號傳遞資訊,主要用來與 sigqueue() 系統調用配合使用,當然,sigaction()同樣支援非即時訊號的安裝。sigaction()優於signal()主要體現在支援訊號帶有參數。
signal
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler));
第一個參數指定訊號的值,第二個參數指定針對前面訊號值的處理,可以忽略該訊號(參數設為SIG_IGN);可以採用系統預設處理訊號(參數設為SIG_DFL);也可以自己實現處理方式(參數指定一個函數地址)。
如果signal()調用成功,返回最後一次為安裝訊號signum而調用signal()時的handler值;失敗則返回SIG_ERR。
sigaction
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
sigaction函數用於改變進程接收到特定訊號後的行為。該函數的第一個參數為訊號的值,可以為除SIGKILL及SIGSTOP外的任何一個特定有效訊號(為這兩個訊號定義自己的處理函數,將導致訊號安裝錯誤)。第二個參數是指向結構sigaction的一個執行個體的指標,在結構 sigaction的執行個體中,指定了對特定訊號的處理,可以為空白,進程會以預設方式對訊號處理;第三個參數oldact指向的對象用來儲存原來對相應訊號的處理,可指定oldact為NULL。如果把第二、第三個參數都設為NULL,那麼該函數可用於檢查訊號的有效性。
第二個參數最為重要,其中包含了對指定訊號的處理、訊號所傳遞的資訊、訊號處理函數執行過程中應屏蔽掉哪些函數等等。
訊號的發送
發送訊號的主要函數有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。
未完待續……