lienhua34 1 信號的概念維基百科中關(guān)于信號的描述是這樣的:
關(guān)于這段描述,我們可以從中學(xué)習(xí)到下面幾點(diǎn)關(guān)于信號的知識, 1. 信號是什么:UNIX 進(jìn)程間的一種異步通訊機(jī)制,。 2. 信號的作用:提醒目標(biāo)進(jìn)程某事件的發(fā)生,并中斷了目標(biāo)進(jìn)程正常的控制流程,。 3. 進(jìn)程對信號的處理:目標(biāo)進(jìn)程可以執(zhí)行信號的默認(rèn)處理函數(shù),或者執(zhí)行進(jìn)程自定義的信號處理程序。 每個信號都有一個名字, 這些名字都以三個字符 SIG 開頭,。 例如,SIGABRT是夭折信號, 當(dāng)進(jìn)程調(diào)用 abort 函數(shù)時產(chǎn)生這種信號,。SIGALRM 是鬧鐘信號,當(dāng)由 alarm 函數(shù)設(shè)置的計時器超時后產(chǎn)生此信號。在 UNIX 系統(tǒng)中,這些信號都定義在頭文件 <signal.h> 中,并且都是以一個正整數(shù)來表示(信號編號),。通過在 shell 中運(yùn)行命令 kill -l 可以查看當(dāng)前系統(tǒng)所執(zhí)行的所有信號,。 UNIX 系統(tǒng)規(guī)定了內(nèi)核可以對信號執(zhí)行以下三種處理行為, 1. 忽略此信號,。有兩個信號 SIGKILL 和 SIGSTOP 不可忽略,這兩個信號提供給超級用戶終止或停止進(jìn)程的可靠方法。 2. 執(zhí)行系統(tǒng)默認(rèn)動作,。大多數(shù)信號的默認(rèn)動作是終止進(jìn)程,。 3. 捕獲信號,執(zhí)行用戶自定義的處理函數(shù)。 2 設(shè)置信號處理程序UNIX 系統(tǒng)提供了 signal 函數(shù)來設(shè)置信號的處理程序,
其中,參數(shù) func 的值可以是, · 常 量SIG_IGN, 向 內(nèi) 核 表 示 忽 略 此 信 號 (有 兩 個 信 號 SIGKILL 和SIGSTOP 不可忽略,調(diào)用 signal 函數(shù)會報錯),。 · 常量SIG_DFL,表示執(zhí)行信號的系統(tǒng)默認(rèn)動作,。 · 一個函數(shù)指針,表示信號發(fā)生時執(zhí)行該函數(shù)進(jìn)行處理,這個函數(shù)稱為信號處理程序。信號處理函數(shù)接收一個 int 類型的信號值參數(shù),無返回值,。 signal 信號的返回值也是一個函數(shù)指針,指向該信號之前的信號處理程序,。 下面我們來看一個例子,
signaldemo.c
上面 signaldemo.c 程序?yàn)樾盘?SIGUSR1 和 SIGUSR2 設(shè)置了信號處理程序sig_usr。然后在主流程 main 中循環(huán)調(diào)用 pause 等待信號,pause函數(shù)使調(diào)用進(jìn)程掛起直至捕捉到一個信號,
只有執(zhí)行了一個信號處理程序并從中返回,pause 函數(shù)才返回,。 編譯 signaldemo.c 程序,生成并執(zhí)行 signaldemo 文件, lienhua34:demo$ gcc -o signaldemo signaldemo.c lienhua34:demo$ ./signaldemo & [1] 3033 lienhua34:demo$ kill -USR1 3033 lienhua34:demo$ received SIGUSR1 kill -USR2 3033 lienhua34:demo$ received SIGUSR2 kill 3033 其中 kill -USR1 3033 和 kill -USR2 3033 分別表示向進(jìn)程 ID 為 3033 的進(jìn)程發(fā)送信號 SIGUSR1 和 SIGUSR2;而 kill 3033 表示向進(jìn)程 3033 發(fā)送信號 SIGTERM,該信號會終止進(jìn)程,。 說明一下信號 SIGUSR1 和 SIGUSR2,這是 UNIX 定義的兩個用戶定義信號。一個 UNIX 系統(tǒng)支持的信號類型是固定,用戶不能夠新增加信號類型,。如果用戶希望通過信號的機(jī)制來實(shí)現(xiàn)自己的功能,則可以通過自定義信號 SIGUSR1 或 SIGUSR2 的信號處理程序來實(shí)現(xiàn)自己想要的功能,。例如維基百科中舉的幾個例子,
3 向進(jìn)程發(fā)送信號UNIX 系統(tǒng)提供了兩個函數(shù) kill 和 raise 來產(chǎn)生信號。kill 函數(shù)將信號發(fā)送給指定的進(jìn)程或進(jìn)程組,。raise 函數(shù)則允許進(jìn)程向自身發(fā)送信號,。
調(diào)用 raise(signo) 等價于 kill(getpid(), signo)。 kill 函數(shù)的 pid 參數(shù)有 4 種不同情況: (1)pid>0 將信號發(fā)送給進(jìn)程 ID 為 pid 的進(jìn)程,。 (2)pid==0 將信號發(fā)送給與發(fā)送進(jìn)程屬于同一個進(jìn)程組的所有進(jìn)程,而且發(fā)送進(jìn)程具有向這些進(jìn)程發(fā)送信號的權(quán)限,。 (3)pid<0 將信號發(fā)送給其進(jìn)程組 ID 等于 pid 的絕對值的所有進(jìn)程,而且發(fā)送進(jìn)程具有向這些進(jìn)程發(fā)送信號的權(quán)限。 (4)pid==-1 將信號發(fā)送給發(fā)送進(jìn)程有權(quán)限向他們發(fā)送信號的系統(tǒng)上的所有進(jìn)程,。 上面有兩點(diǎn)需要說明一下:(1)“所有進(jìn)程”不包括系統(tǒng)進(jìn)程集;(2)發(fā)送進(jìn)程是超級用戶,或者發(fā)送進(jìn)程的實(shí)際或有效用戶 ID 等于接收進(jìn)程的實(shí)際或有效用戶 ID 才具有發(fā)送信號權(quán)限,。下面來看個例子,
killdemo.c
上面的 killdemo.c 程序文件中,父進(jìn)程為信號 SIGUSR1 和 SIGUSR2設(shè)置了信號處理程序sig_usr。然后調(diào)用 fork 創(chuàng)建一個子進(jìn)程,子進(jìn)程的信號 SIGUSR1 和 SIGUSR2 的信號處理程序繼承父進(jìn)程的,同樣是sig_usr(除非子進(jìn)程調(diào)用了 exec 函數(shù),子進(jìn)程中這兩個信號的信號處理動作才會設(shè)置為系統(tǒng)默認(rèn)),。父進(jìn)程調(diào)用 kill 函數(shù)向子進(jìn)程發(fā)送信號 SIGUSR1,而調(diào)用 raise 函數(shù)向自身發(fā)送信號 SIGUSR2. 編譯該程序,生成并執(zhí)行 killdemo文件, lienhua34:demo$ ./killdemo process 3261 creates a child process 3262 process 3261 received SIGUSR2 process 3262 received SIGUSR1 通過上面的運(yùn)行結(jié)果,可以看到父進(jìn)程 3261 創(chuàng)建了子進(jìn)程 3262,父進(jìn)程 3261 捕獲了信號 SIGUSR2,子進(jìn)程捕獲了信號 SIGUSR1,。實(shí)際運(yùn)行結(jié)果與預(yù)期結(jié)果相符合,。 (done) |
|