APUE筆記之10章 訊號

2021-09-12 01:44:55 字數 4959 閱讀 5424

訊號是軟體中斷。訊號提供非同步事件處理方法。

早期的訊號模型 不可靠,訊號可能丟失。posix.1對可靠訊號例程進行了標準化。

呼叫kill(2)函式可將任意訊號傳送給另乙個程序或程序組,但有限制:

當某個訊號出現時,核心有3種處理方式:

忽略:有2種訊號不能被忽略 -sigkill 和 sigstop, 原因是:它們向核心和超級使用者提供了使程序終止或停止的可靠方法;

捕捉:比如,若捕捉到sigchld訊號,則表示乙個子程序已經終止,所以sigchld訊號的捕捉函式可呼叫 waitpid 以取得該子程序的程序id和它的終止狀態。又比如,若程序建立了臨時檔案,那麼要為 sigterm 訊號編寫乙個訊號捕捉函式以清除臨時檔案(sigterm是終止訊號)

執行預設動作:圖10-1給出了每一種訊號的系統預設動作(p251)。大多數訊號的系統預設動作是終止該程序。

常見訊號及發生原因:

sigabrt 

呼叫abort函式時產生此訊號;程序異常終止。

sigalrm 

程序所設定的定時器超時

sigchld

當乙個程序終止或停止時,sigchld被送給其父程序;系統預設忽略此訊號;若父程序希望被告知,則其應該捕捉此訊號,在訊號處理函式中呼叫一種wait函式以取得子程序的id和終止狀態。

sigcont

這是作業控制訊號,傳送給需要繼續執行,但當前處於停止狀態的程序。若程序沒有處於停止狀態,則預設動作是忽略此訊號。

sigfpe

算術運算異常,如除以0、浮點移出

sighup

終端介面檢測到乙個連線斷開,則將此訊號傳送給與該終端相關的控制程序(即會話首程序)

sigint

中斷訊號,由ctrl+c產生,用來停止程式;

sigio

乙個非同步i/o事件產生了

sigkill

用來殺死程序,不能被忽略

sigpipe 

在管道的讀程序已終止後,乙個程序寫此管道,則產生此訊號;

sigquit

ctrl+\ ,不僅終止前台程序組,而且產生乙個core檔案

sigse**

無效的記憶體訪問

sigstop

這是乙個作業控制訊號,停止乙個程序;不能被忽略

sigterm

一般讓該訊號的捕捉函式在程式退出之前做好清理工作,從而優雅地終止

sigtstp

互動停止訊號;當使用者在終端上按 ctrl+z 後,終端驅動程式產生此訊號。該訊號傳送給前台程序組的所有程序。

#include void (*signal(int signo, void(*func)(int)))(int);
這個原型太複雜了,使用下面的typedef會簡單一些:

typedef void sigfunc(int);

sigfunc *signal(int, sigfunc *);

簡單來講,signal函式原型是:

檢視系統的標頭檔案signal.h,可以看到下列形式的宣告:

#define sig_err (void (*)())-1

#define sig_dfl (void (*)())0

#define sig_ign (void (*)())1

這些常量用於表示「指向函式的指標,該函式要求乙個整型引數,而無返回值」。這些常量所用的3個值不一定是-1、0、1,但它們必須是3個值而決不能是任一函式的位址。

程式示例:

#include // one handler for 2 signals

static void sig_user(int)

int main()

return 0;

}

程式的啟動

exec函式將原先設定為要捕捉的訊號都更改為預設動作,其他訊號的狀態則不變(乙個程序原先要捕捉的訊號,當其執行乙個新程式後,就不能再捕捉了,因為訊號捕捉函式的位址一般在所執行的新程式檔案中已無意義)。

當程序呼叫fork後,子程序複製了父程序的記憶體映像,所以訊號捕捉函式的位址在子程序中是有意義的。

很多捕捉到sig_int和sig_ign的程式具有下列形式的**:

void sig_int(int);

void sig_quit(int);

if (signal(sigint, sig_ign) != sig_ign) // 若當前未被忽略,才會捕捉

signal(sigint, sig_int);

if (signal(sigquit, sig_ign) != sig_ign) // 若當前未被忽略,才會捕捉

signal(sigquit, sig_quit);

不可靠指的是,訊號可能會丟失。

有時候使用者希望通知核心阻塞某個訊號,即:不忽略該訊號,在其發生時記住它,在程序做好了準備時再通知它。這種阻塞訊號的能力,在早期並不具備。

早期的unix系統:如果程序在執行乙個低速系統呼叫而阻塞時,捕捉到乙個訊號,則該系統呼叫就被中斷而不再執行。

後來的unix系統:捕捉到訊號並處理後,會返回已讀或已寫的部分,從而視該系統呼叫為成功。

4.2bsd引入了一些被中斷後可以自動重啟動的系統呼叫:ioctl、read、readv、write、writev、wait、waitpid. 

前5個函式只有對低速裝置操作時才會被訊號中斷,而wait和waitpid在捕捉到訊號時則總是被中斷。

4.3bsd允許程序基於每個訊號禁用此自動重啟動的功能。

系統呼叫可分為2類:低速系統呼叫和其他系統呼叫。

低速系統呼叫是可能會使程序永遠阻塞的一類系統呼叫。如,讀管道、終端、網路裝置時,資料不存在。

下列是一些不可重入函式的特徵:

使用了靜態的資料結構

呼叫了malloc或free

是標準i/o函式,因為標準i/o庫的很多實現都以不可重入的方式使用全域性資料結構

作為一種通用的規則,當在訊號處理程式中呼叫圖10-4中的這些可重入函式時,應當在呼叫前儲存errno,在呼叫後恢復errno. 

在訊號處理程式中,呼叫乙個不可重入函式,其結果是不可預知的。舉個栗子,當主程式中呼叫free時被訊號中斷,而訊號處理程式中也呼叫了free,那麼malloc和free維護的資料結構就遭到了破壞,從而程式會執行出錯。

sigcld是systemv的乙個訊號名,其語義與名為sigchld的bsd訊號不同。posix.1採用bsd的sigchld訊號。

bsd的sigchld的語義是,子程序改變狀態後產生此訊號,父程序需要呼叫乙個wait函式以檢測發生了什麼。

對於sigcld的處理方式(略)

注意,linux3.2.0和solaris 10定義了sigcld,其等同於sigchld.

當乙個訊號產生時,核心通常在程序表中以某種形式設定乙個標誌。當核心做這個動作時,我們稱為「向程序遞送了乙個訊號」。

在訊號產生(generation)和遞送(delivery)之間的時間間隔,稱訊號是未決的(pending)

程序可以「阻塞訊號遞送」。如果為程序產生了乙個阻塞的訊號,而且訊號處理動作是系統預設動作(sig_dfl)或捕捉該訊號,那麼該程序將此訊號保持為未決狀態,直到該程序對此訊號解除了阻塞或對此訊號的動作更改為忽略。

程序呼叫sigpending 函式來判定哪些訊號是設定為阻塞並處於未決狀態的。

如果在程序解除對某個訊號的阻塞之前,該訊號發生了多次,將如何呢?

posix.1允許系統遞送該訊號一次或多次。若遞送多次,則稱這些訊號排隊了。但除非支援posix.1的實時擴充套件,否則大多數unix並不對訊號排隊,而只遞送一次。

若有多個訊號要遞送給乙個程序,posix.1並沒有規定這些訊號的遞送順序。但posix.1基礎部分建議:在其他訊號之前遞送與程序當前狀態有關的訊號,如sigse**. 

每個程序都有乙個訊號遮蔽字(signal mask),它規定了當前要阻塞而不遞送到該程序的訊號集。對於每種可能的訊號,該遮蔽字中都有一位與之對應。對於某種訊號,若其對應位已經設定,則它當前是被阻塞的。程序可以呼叫sigprocmask 函式來檢測和更改其當前的訊號遮蔽字。

訊號編號可能會超過乙個整型的二進位制位數,因此posix.1定義了乙個新資料型別sigset_t, 它可以容納乙個訊號集。

資料型別訊號集(signal_set)被函式sigprocmask用於告訴核心不允許發生在該訊號集中的訊號。

下面是處理訊號集的函式

#include int sigemptyset(sigset_t *set);  // 清除訊號集中的所有訊號

int sigfillset(sigset_t *set); // 初始化由set指向的訊號集,使其包括所有訊號

int sigaddset(sigset_t *set, int signo); // 講乙個訊號signo新增到訊號集set中

int sigdelset(sigset_t *set, int signo); // 從訊號集中刪除乙個訊號

// 以上4個函式,若成功,返回0,失敗返回-1

int sigismember(const sigset_t * set, int signo); // 判斷訊號signo是否在訊號集set內

posix.1認為有以下6個與作業控制有關的訊號:

其他略略

(完)

APUE讀書筆記 第10章 訊號

第10章 訊號 10.1 引言 訊號是軟體中斷。訊號提供了一種處理非同步事件的方法 10.2 訊號概念 每個訊號都有乙個名字。這些名字都以三個字元sig開頭 在標頭檔案中,這些訊號被定義為正整數 訊號編號 不存在編號為0的訊號。kill函式對訊號編號0有特殊的應用。此種訊號編號值被稱為空訊號 10....

APUE學習筆記 10 訊號概念

by 潘雲登 對於商業目的下對本文的任何行為需經作者同意。寫在前面 1.本文內容對應 unix 環境高階程式設計 第 2版 第 10章。2.總結了有關訊號的基本概念,包括訊號產生的原因和對訊號的處理方式。3.訊號概念 訊號是軟體中斷,提供了一種處理非同步事件的方法。每個訊號都有乙個名字,以字元 si...

APUE第十章 訊號

同步 乙個程序在執行某個請求的時候,若該請求需要一段時間才能返回資訊,那麼這個程序將會一直等待下去,直到搜到返回資訊才繼續執行。非同步 乙個程序在執行某個請求的時候,不需要一直等下去,而是繼續執行之後的操作,有訊息返回時系統會通知程序進行處理。同步和非同步關注的是程序之間的訊息通訊機制,區別阻塞和非...