Linux訊號 程序間非同步的通訊機制

2021-08-26 12:37:20 字數 4428 閱讀 7942

一 、 概念和功能:

訊號實際上是乙個軟中斷,用於通知程序發生了某些事,該如何處理。

實際上也歸為一類程序間通訊方式, 訊號的生命週期:訊號的產生-訊號的註冊-訊號的阻塞(/遮蔽)-訊號的登出-訊號的處理

二 、 檢視訊號:

kill -l ,檢視linux下全部訊號,可看出訊號是由編號和巨集組成;

kill並不是殺死乙個程序,而是為了給某乙個指定的程序傳送訊號。

linux下有62 個訊號,分為兩類:1-31是非可靠訊號(並非實訊號),1-31是繼承unix而來的,每個訊號都對應乙個指定事件,非可靠代表這個訊號可能會丟失,如果有相同的訊號已經註冊到這個程序沒有被處理,那麼接下來的相同訊號就會丟掉。

34-64,為可靠訊號(實訊號)

三 、訊號產生方式:

1.硬體中斷 (鍵盤按鍵中斷,ctrl c);

2.硬體異常; (段錯誤,記憶體訪問錯誤,core dump,預設發生的訊號是11 號sigsegv)

3.命令產生:kill 命令 (kill -n pid),預設情況下傳送的是訊號15sigterm

4.軟體條件產生:kill函式,raise函式,alarm函式,sigqueue函式

給程序傳送訊號的介面函式

int kill(pid_t pid,int sig)         //向指定程序傳送訊號

引數:程序id,指定傳送給哪個程序 ;訊號的編號,指定傳送哪個訊號 (訊號是由編號和巨集組成 2 siginit)

int raise(int sig) //給當前程序傳送訊號

int sigqueue(pid_t pid,int sig,union sigval value) //給指定程序傳送訊號,並且可以傳乙個引數過去,value是要攜帶的資料,其型別是union sigval

unsigned int alarm(unsigned int seconds)//在指定second秒後給程序傳送訊號

四 、 core dump

當乙個程式要異常終止時,可以選擇吧程序使用者空間記憶體資料全部儲存到磁碟上,檔名通常是core,這叫做core  dump。

程式異常的時候,會記錄乙個核心轉儲檔案,在這個檔案中記錄程式執行資料 。當乙個程式奔潰時,這個錯誤可能只是偶爾發生,這種錯誤將很難定位,因為不確定到底什麼時候才會崩潰,因此這個轉儲檔案(core 檔案)就非常重要,它可以幫助我們使用gdb除錯 檢視,定位錯誤。

ulimit -c size ,可以設定core dump的大小,例如 ulimit -c 1024

gdb進出程式,執行執行程式(run ),bt,用來檢視呼叫棧。在gdb中使用命令:core-file core.3996()來引導程式的的執行資料,然後就可以定位錯誤了。 但是程式的核心轉儲功能是**預設關閉的**,轉儲檔案預設大小為0,因此執行資料中可能有安全性資訊,以及檔案增多會占用資源 檢視檔案/改變檔案的大小:

將訊號記錄在程序中,讓程序知道有這樣乙個訊號來了。

訊號是記錄在程序的pcb中 。

訊號集合:在pcb中sigset_t 結構體

程序記錄乙個訊號的時候,通過這個結構體的位圖來記錄

註冊:修改程序中pcb中訊號pending的點陣圖,新增乙個訊號的sigqueue結構體節點(pending點陣圖0變1)

登出:修改程序中pcb中訊號pending的點陣圖,刪除指定訊號的sigqueue的結構體節點(pending點陣圖1變0)

訊號阻塞:因為程序pcb 中還有乙個結構,這個結構就是block阻塞集合,

在pcb中有 乙個pending結構中儲存當前接收到的訊號,還有乙個結構體blocked用於儲存 現在有哪些訊號要被阻塞。 程序看到了pending集合中都收到了哪些訊號,然後就要開始處理這些訊號,但在處理這些訊號之前,程序先比對一下這些訊號有沒有存在於blocked集合中,如果存在了(點陣圖為1),意味著現在這個訊號不被處理,直到解除阻塞 。

訊號阻塞介面:

阻塞: int sigprocmask(int how,sigset_t *set,sigset_t *oldset)

how:對集合所做的操作,sig_block(對set集合,sig_unblock,sig_setmask

實現訊號阻塞遮蔽

//先定義集合

//將訊號新增到集合中:intsigfillset(sigset_t *set);

int sigpending(sigseet_t set)//將當前pending集合中的訊號取出來放到set中 int sigismember(const sigset_tset,int signum) 判斷訊號是否在集合中

就是從pending中將要處理的訊號移除但分情況: 非可靠訊號: 註冊的時候,是給sigqueue鍊錶新增乙個訊號結點,並且將pending集合對應點陣圖置1,當這個訊號註冊的時候,如果位圖已經置1,代表訊號已經註冊過了,那就不做任何操作,不新增新結點 登出:刪除鍊錶中的節點,將對應點陣圖置 0 可靠訊號: 註冊:是給sigqueue鍊錶新增乙個訊號節點,不管這個可靠訊號是否已經註冊過,如果沒有註冊過,就新增新節點,對應點陣圖置1 登出:刪除乙個節點,然後檢視鍊錶中有沒有相同的節點,如果有,那麼訊號對應的點陣圖 110 依然為1,若果沒有相同的節點,代表這個訊號全部被處理,因此對應點陣圖置0 111 112 可靠訊號因為每次訊號到來都會新增新節點,所以不會丟失訊號。

#訊號處理(訊號的遞達)

當程序收到乙個訊號時,就意味著現在有乙個重要的事情要處理,因此會打斷我們當前的操作,然後去處理這件事

訊號的處理方式:

預設處理:系統定義好的處理方式

忽略處理方式:忽略和阻塞完全不同,乙個被忽略的訊號來了以後就直接丟棄

自定義處理方式:使用者自己定義乙個的乙個處理訊號的方式,使作業系統按照定義的這個處理方式來處理這個訊號

訊號忽略和訊號註冊的區別,阻塞乙個訊號後,訊號依然會註冊在pending集合中,而忽略訊號,則訊號直接丟棄,不會註冊

訊號處理方式介面:

sighandler_t signal (int signum, sighandler_t handler)

功能:修改乙個訊號的處理方式

引數:指定修改哪個訊號; 第二個是處理的方式,sig_ign(忽略處理),sig_dfl(預設處理)

int sigaction(int signum,const struct signation *act, struct signation *oldact)

功能:修改訊號的處理方式

引數:signum指定修改哪個引數;act是指定的處理動作;oldact 儲存訊號原來的處理方式

結構體:

struct sigaction ;

針對自定義處理方式,程序捕捉到訊號然後進行處理的 過程

程序是從核心態切換到使用者態時,需要判斷是否有訊號要處理,然後返回使用者態去自定義處理,在返回核心,在返回使用者態

如何實現從使用者態到記憶體態的切換?中斷,異常,系統呼叫

可重入函式:某個函式呼叫的時候,如果中間操作被打斷,在其他地方有重複多次呼叫,不影響執行結果(對其他地方的呼叫產生影響),這個函式就叫可重入函式

不可重入函式:多次呼叫影響結果。

可重入函式的特點:操作了一些公共資料

如果我們的某個操作不是乙個原子操作,那麼意味著這個操作有可能被打斷然後去做其他的事情,這時做其他事情可能產生一些邏輯問題

int  sigsuspend(const sigsey_t *mask)     

//集合了臨時阻塞指定訊號,並陷入阻塞等待的乙個原子操作

功能:臨時使用mask中的訊號替換阻塞結合blocked中的訊號,然後進入阻塞等待,喚醒後還原。

也就是說臨時替換阻塞訊號,進入休眠,喚醒時 ,在將原來的阻塞訊號替換回

自己寫的sleep為例,講解競態條件,說的是alarm函式和pause函式間如果被打斷去幹其他事情,可能造成pause永久阻塞

因為程式在優化的時候,如果乙個變數使用的頻率很高的話(比如全域性變數)那麼,這個變數有可能被優化為只向記憶體器載入一次,往後直接使用暫存器中儲存的值。 而不關心它在記憶體裡的值,因此可能會造成一些邏輯錯誤

sigchild 訊號

自定義處理,迴圈的原因是對子程序資源隨退隨**,且大致不影響邏輯。

訊號是會打斷程序的阻塞操作,喚醒正在休眠的程序

Linux程序間通訊之非同步訊號

在linux系統當中有62個訊號,可以通過 kill l 這個命令檢視如下圖所示 可以看到圖中的訊號分為兩個風格1 31是有獨自的名字,而34 64名字都是相同的。1 31是非實時訊號,34 64是實時訊號。關於訊號在man手冊中的第七本signal有詳細的說明。signal 忽略訊號,捕捉訊號,恢...

Linux 程序間通訊 訊號

訊號是在軟體層次上對中斷機制的一種模擬,在原理上,乙個程序收到乙個訊號與處理器收到乙個中斷請求可以說是一樣的。訊號是非同步的,乙個程序不必通過任何操作來等待訊號的到達,事實上,程序也不知道訊號到底什麼時候到達。訊號是程序間通訊機制中唯一的非同步通訊機制,可以看作是非同步通知,通知接收訊號的程序有哪些...

Linux程序間通訊 訊號

1.什麼是訊號 訊號是linux系統響應某些條件而產生的乙個事件,接收到該訊號的程序會執行相應的操作。2.訊號的產生 1 由硬體產生,如從鍵盤輸入ctrl c可以終止當前程序 2 由其他程序傳送,如可在shell程序下,使用命令 kill 訊號標號 pid,向指定程序傳送訊號。3 異常,程序異常時會...