unix環境高階程式設計之訊號篇(一)

2021-07-09 16:09:04 字數 3631 閱讀 8079

一、引言:

訊號是軟體中斷,很比較重要的應用程式都需要處理訊號。訊號提供了一種處理非同步事件的方法,例如,中斷使用者鍵入中斷鍵,則會通過訊號機制停止乙個程式,或及早終止管道中的下乙個程式。

二、概念:

每乙個訊號都有乙個名字。這些名字都是以sig開頭,如sigabrt是夭折訊號,當程序呼叫abort函式時產生這種訊號。sigalrm是鬧鐘訊號,當由alarm函式設定的計時器超時後產生此訊號。

在標頭檔案中,訊號都會被定義成正整數。核心包括對使用者級別應用程式有意義的標頭檔案,這被認為是一種糟糕的形式,所以如果應用程式和核心兩者都需要使用同一種定義,那麼久需要將有關資訊放置在核心標頭檔案中,然後再使用者級標頭檔案中再包括該核心標頭檔案。

不存在編號為0的訊號,kill函式都訊號編號為0的油特殊的應用。此種訊號稱為空訊號。

訊號是非同步事件的一種經典例項。產生訊號的事件對程序而言是隨機出現的,程序不能簡單的測試乙個變數如errno來判斷是否出現乙個訊號,二是必須告訴核心「在出現這種訊號時應該執行下列操作」。

可以要求核心在某個訊號出現時按照下列三種方式之一去處理,我們稱之為訊號的處理或者訊號的相關的動作。

1、忽略此訊號。大多數訊號都可以使用這種訊號,但是有兩種訊號不能忽略:sigkill和sigstop,因為這兩種訊號向超級使用者

提供了可以終止或者停止任何程序的可靠方法。另外,如果程序發生硬體異常的話,如果被忽略,程序的執行行為是不可**的。

2、捕捉訊號。為了做到這一點,要通知核心在某種訊號發生時呼叫乙個使用者函式,在使用者函式中,可執行使用者希望對這種時間的處理。

3、執行預設操作。每一種訊號系統都提供了預設的操作。注意,針對大多數訊號的預設操作動作是終止程序。

需要注意:如果程序在處理乙個訊號返回前的時候有產生了乙個訊號,那麼同等或高優先順序的訊號會中斷低優先順序的訊號處理

三、常用訊號詳解

sigabrt:呼叫abort函式時產生此訊號,程序異常終止

sigalrm:在呼叫alarm函式設定的計時器超時時,產生此訊號,若有setitimer(2)函式設定的間隔時間超時,也會產生此訊號

sigbus:指示乙個實現定義的硬體故障,如出現某個型別的記憶體故障時會產生此訊號

sigchld:當乙個程序終止或者停止時,傳送這個訊號給其父程序,按系統預設,將忽略此訊號。如果父程序希望被告知其子程序的這種狀態的改變,則應捕捉此訊號。捕捉函式中通常呼叫乙個wait函式以取得子程序id和其終止狀態

sigfpe:此訊號表示乙個算術運算異常,例如除以0,浮點溢位等。

sighup:中斷介面連線斷開,將此訊號傳送給與該中端相關的控制程序

sigill:此訊號指示程序已執行一條非法硬體命令

siginfo:bsd訊號,使用者按狀態鍵(ctrl+t),終端驅動程式產生此種訊號並送至前台程序組中的每乙個程序,此訊號經常導致在終端上顯示前台程序組中各程序的狀態資訊

sigint:當使用者按下中斷鍵時(delete或者crtl+c),終端產生此訊號並送至前台程序組中的每乙個程序。當乙個程序失控時,常用此訊號終止它

sigkill:這是兩個不能被忽略的訊號之一,它向系統管理員提供了一種可以殺死任意程序的可靠方法

sigpipe:如果在寫管道時讀程序已經終止,則產生此訊號。當型別為sock_stream的套接字已不在連線時,程序寫到該套接字也產生此訊號

sigquit:使用者按下退出鍵(ctrl+\),產生此訊號,並送至前台程序組中的每乙個程序,此訊號不僅終止前台程序組(如sigint),還會產生core檔案

sigsegv:該訊號指示程序進行了一次無效記憶體的引用

sigstop:這是乙個作業控制訊號,使用者停止乙個程序。它類似於互動停止訊號(sigtstp),但是這個訊號不能被忽略

sigsys:此訊號指示乙個無效的系統呼叫,如版本不支援的系統函式呼叫

sigterm:這是由kill(1)命令傳送的系統預設終止訊號

sigtstp:互動時停止訊號,使用者按下(ctrl+z)時產生,

sigusr1:使用者自定義訊號1

sigusr2:使用者自定義訊號2

sigvtalrm:當乙個有setitimer(2)函式設定的虛擬間隔時間到期時產生此訊號。

四、signal函式

說了那麼多,訊號接收和處理使用哪個系統api呢?unix系統訊號機制最簡單的藉口是signal函式。

#include

void (*signal(int signo,void(*func)(int)))(int);

返回值:若成功則返回訊號以前的處理配置,出錯返回sig_err;

signo:該引數是上述三中的訊號名,包括但不僅限於此。

func:該引數可以是常量sig_ign,或者常量sig_dfl,或者接收到訊號時需要呼叫的函式的位址。

如果是sig_ign,則向核心表示忽略此訊號,(記住有兩個訊號不能忽略)

如果是sig_dfl,則表示接收到訊號時執行系統預設的動作

如果是指定函式位址,則在發生和接收到訊號時,呼叫該函式,我們稱這種處理為捕捉訊號。此函式稱為訊號處理程式或者訊號捕捉函式

signal函式原型說明該函式需要兩個引數,並且返回乙個函式指標,而該函式指標所指向的函式是無返回值的(void*)而且需要乙個整形引數(最後的int)。

第乙個引數signo是乙個整數(其實就是訊號編號),第二個引數是乙個函式指標,該函式需要乙個整形引數,無返回值。

signal的返回值其實指向之前的訊號處理函式的指標。這句話得意思是:

signal(sigusr1,sig_usr1);//此時應該返回值為系統預設處理動作值,也就是sig_dfl

...signal(sigusr1,sig_usr2);//這時返回值的函式指標就指向了sig_usr1

系統的中會找到以下形式的宣告:

define sig_err

(void (*) ())-1

define sig_dfl

(void (*) ())0

define sig_ign

(void (*) ())1

簡單例子sig.c:

#include

#include

static void sig_usr(int signo)

int main()

$./sig &後台啟動

[1]7172作業控制shell列印作業和程序號

$kill -sigusr1 7172向程序傳送sigusr1訊號

recv sig_usr1

$kill -sigusr2 7172向程序傳送sigusr2訊號

recv sig_usr2

$kill 7172 向程序傳送sigterm訊號

[1]+已終止./sig

五、可重入函式和不可重入函式

可重入函式:在執行時,允許中斷,然後返回;

不可重入函式:在執行函式時,由於函式內部存在諸如全域性資料結構變數,所以不允許被中斷

不可重入的原因:1、函式中使用了一些全域性資料結構

2、函式呼叫了malloc和free

3、它們是標準i/o函式,標準i/o庫的實現很多都利用了全域性資料結構

如果在訊號處理函式中呼叫了乙個不可重入函式,那麼程序的執行結果是不可**的,程序很容易被sigsegv訊號終止

unix環境高階程式設計之執行緒篇(一)

本章介紹執行緒篇,第一篇先著重講執行緒標識,建立,終止以及一些需要注意的東西,後續繼續更新執行緒同步。一 執行緒標識 就像每個程序擁有乙個自己的程序id一樣,每個執行緒也擁有自己的乙個執行緒id。程序id在整個系統中是唯一的,但是執行緒id不同,它只在它所屬的程序環境中有效。程序id有個資料型別pi...

unix 環境高階程式設計之訊號一 概念

為了理解訊號,先從最熟悉的場景說起 1 使用者輸入命令,在shell中啟動乙個前台程序。2 使用者按下ctrl c,這個鍵盤輸入產生乙個硬體中斷 3 如果cpu當前正在執行這個程序的 則該程序的使用者空間 暫時停止執行,cpu從使用者態切換到核心態處理硬體中斷 4 終端驅動程式將ctrl c解釋為乙...

UNIX環境高階程式設計之第10章 訊號

訊號是軟體中斷.很多比較重要的應用程式都需要處理訊號.訊號提供一種處理非同步時間的方法,例如,終端使用者鍵入中斷鍵,會通過訊號機制停止乙個程式,或及早終止管道中的下乙個程式.首先每個訊號都有乙個名字.這些名字都是以sig開頭.例如,sigabrt是夭折訊號,當程序呼叫abort函式是產生這種訊號.u...