linux:進程中信號的“3種狀態 And 3張表”


高能預警


本文主要介紹了信號在進程pcb中的表示方法並用代碼驗證其真實性。

主要內容有:

1.信號在進程中的表示方法:3種狀態—3張表

2.對上述方法進行代碼驗證,包括:

  • 信號集(sigset_t)和信號屏蔽字(Signal Mask)及信號集操作函數的介紹
  • 代碼驗證(pending表)

————>全文閱讀大概需要5min(我發四)<————


3種狀態 And 3張表


在博主上篇博文中降到進程收到信號後,其可選的處理動作有以下三種:

1.忽略此信號。
2.執⾏行該信號的默認處理動作(終止該信號)。
3.提供⼀個信號處理函數(自定義動作),要求內核在處理該信號時切換到用戶態執行這個處理函數,這種方式稱爲捕捉(Catch)一個信號。
歡迎大家圍觀:linux信號基本概念及如何產生信號

而這3種處理動作屬於信號的第3種狀態信號遞達(進程對信號的實際處理動作)

很明顯,信號遞達是信號已經被進程接收時的狀態。

而信號在沒有發給進程之前,有兩種狀態:

第1種:信號阻塞(被阻塞的信號產生時將一直保持在未決狀態,直到進程解除對此信號的阻塞, 才執⾏遞達的動作)

第2種:信號未決(信號從產生到遞達之間的狀態)

一定要區分阻塞和忽略的區別:

1.忽略是進程對信號的一種處理方式,它屬於信號遞達狀態。而阻塞是跟信號遞達同級的概念。

2.只要信號被阻塞就不會遞達,而忽略是在遞達之後可選的一種處理動作。

3種狀態說完了,下面我們來看信號在進程pcb中是如何存儲的,具體來說,就是3張表:

1

這3張表分別對應3種狀態:

  • 信號阻塞(block)
  • 信號未決(pending)
  • 信號遞達—自定義捕捉函數(handler)

其中,前兩張表都是位圖(BitSet)來存儲的。信號被阻塞就將相應位置1,否則置0。而pending表中,若置1則表示信號存在,0則相反。換句話說,pending表中的數據是判斷信號是否存在的唯一依據。

此外,上圖中還有3個例子,結合上邊的概念就可以知道:

  1. SIGALRM信號未阻塞也未產生過,但當它遞達時就會執行默認處理動作。
  2. SIGINT信號產生過,但已被阻塞。所以暫時不能遞達。雖然它的處理動作是忽略。但在沒有解除阻塞之前不能忽略這個信號,因爲進程仍有機會改變處理動作之後再解除阻塞。
  3. SIGQUIT信號未產生過,一旦產⽣將被阻塞,它的處理動作是用戶自定義的捕捉函數handler。

還有一個問題:如果在進程解除對某信號的阻塞之前這種信號產生多次,將如何處理?

POSIX.1標準允許系統遞送某信號一次或多次。Linux是這樣實現的:常規信號(1-31)在遞達之前產⽣生多次只計一次。而實時信號(34-64)在遞達之前產生多次可以依次放在一個隊列裏。


信號集(sigset_t)和信號屏蔽字(Signal Mask)


在上圖中,未決和阻塞標誌都可以用相同的數據結構(位圖)存儲。所以當然可以用同一數據類型來表示,這就是sigset_t.

sigset_t稱爲信號集,這個類型可以表示每個信號的“有效”或“無效”狀態。在阻塞信號集其含義是該信號是否被阻塞;在未決信號集中就代表該信號是否處於未決狀態。

阻塞信號集也叫做當前進程的信號屏蔽字(Signal Mask),這裏的“屏蔽”應該理解爲阻塞而不是忽略。


既然未決和阻塞狀態都是用位圖來表示的,那麼能不能用移位操作來改變信號狀態呢?,當然是——不行的。系統對於信號集有特定的信號集操作函數,所以不能用移位操作。只能調用這些操作函數來改變信號狀態。那麼接下來就來看看系統中有哪些信號集操作函數吧:

2

注:在使用sigset_t類型的變量之前,⼀定要調用sigemptyset或sigfillset做初始化,使信號集處於確定的狀態。

此外,系統還提供了信號屏蔽字(block表)的操作函數

3

其中:
1.如果oset是非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。
2.如果set是非空指 針,則更改進程的信號屏蔽字,參數how指示如何更改。
3.如果oset和set都是非空指針,則先將原來的信號屏蔽字備份到oset裏,然後根據set和how參數更改信號屏蔽字。

假設當前的信號屏蔽字爲mask,下表說明了how參數的可選值:

3

注:如果調用sigprocmask解除了對當前若干個未決信號的阻塞,則在sigprocmask返回前,至少將其中一個信號遞達。

還有讀取未決信號集(pending表)的函數

4

因爲信號存不存在是客觀事實,所以系統沒有必要提供對pending表的設置接口。


Code


瞭解了信號集和信號屏蔽字的概念和信號集的各種操作函數。現在我們來編寫代碼測試一下信號的存儲是否真如上邊所說。

step1:屏蔽2號信號後,再使其變爲未決狀態,觀察信號集數據由0變1

代碼:

5

10

執行效果:

6

step2:解除2號信號的阻塞狀態,使其抵達。捕捉到2號信號後,信號集數據又從1變0,變爲以前的狀態。再次crtl+c後,就不會發生1中的變化了。

代碼:

7

執行效果:

11


The End


信號系列文還有最後一篇“信號的捕捉”,博主後續會更新。敬請期待。。。

發佈了54 篇原創文章 · 獲贊 34 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章