在另一篇文章linux訊號中,介紹了訊號的產生與處理方式,以及一系列訊號集函式的使用。
本文使用訊號機制,模擬實現sleep函式並了解競態條件。
在此之前先介紹一波需要用到的函式。
sigaction函式
#include
int sigaction(int signum, const
struct sigaction *act, struct sigaction *oldact);
可以讀取和修改於指定訊號相關聯的處理動作。
引數 signnum 為指定訊號的編號。
若act指標非空,則根據 act 修改訊號的處理動作,oldact可以為空,或者傳出原來的處理動作。act和oldact都指向下面的結構體:
struct sigaction
當某個訊號的處理函式被呼叫時,核心自動將當前訊號加入程序的訊號遮蔽字,當訊號處理函式返回時自動恢復原來的訊號遮蔽字。保證在處理某個訊號時,如果這種訊號再次產生,那麼它會被阻塞到當前處理結束為止。如果在調動訊號處理函式時,還需要遮蔽別的訊號,則可以通過sa_mask 指定。
pause 函式
#include
int pause(void);
掛起呼叫程序直到有訊號遞達。 如果訊號的處理動作是終止程序,則程序終止。如果訊號的處理動作是忽略,則程序繼續處於掛起狀態。只有訊號的處理動作是捕捉pause函式才會返回。
首先來實現 sleep 版本1:
1. 呼叫sigaction()
捕捉訊號sigalrm
2. 呼叫alarm()
設定鬧鐘
3. 呼叫pause()
掛起等待
4. 取消鬧鐘
5. 恢復捕捉動作
#include
#include
// 什麼事情也不做
關於mysleep1有幾個問題:
q1:訊號處理函式handler函式什麼都不幹,為什麼還要註冊它作為sigalrm的處理函式?不註冊訊號處理函式可以嗎*?
答:不可以。因為pause() 函式使程序掛起等待,直到有訊號遞達並且要執行自定義的訊號處理函式才有機會返回。
q2:為什麼在mysleep函式返回前要恢復sigalrm訊號原來的sigaction?
答:main函式作為呼叫者只想睡一下覺,沒叫你在它睡覺的時候把它打的鼻青臉腫的,所以呼叫之前什麼樣就給恢復成什麼樣子。
q3:mysleep函式的返回值表示什麼含義? 什麼情況下返回非0值?重新審視上面**,會發現有乙個bug,假如在設定鬧鐘後,出現大量優先順序較高的程序需要執行,測試該程序就會被切出去,即cpu資源被分配給了別的程序,如果時間很長的話,當該程序再次或者cpu資源的時候,鬧鐘時間已過,而pause永遠不會返回。
出現這個問題的原因是系統執行**的時序是不確定的。如果在寫程式時考慮不周密,可能由於時序問題而導致錯誤,這叫做競態條件(race condition)。
我們可以在設定鬧鐘之前,遮蔽訊號 sigalrm, 在讓程序掛起時,解除對該程序的遮蔽,然後在讓程序掛起等待訊號遞達。可以利用 sigsuspend函式 幫我們圓夢。
#include
int sigsuspend(const sigset_t *sigmask);
和pause 函式一樣,該函式沒有成返回值,只有執行乙個訊號處理函式之後,才會返回。
呼叫sigsuspend時,程序的訊號遮蔽字由sigmask引數指定,可以通過指定sigmask來臨時解除對某個訊號的遮蔽,然後掛起等待,返回時,程序的訊號遮蔽字恢復為原來的值。
下面的從新實現的mysleep2:
1. 捕捉sigalrm訊號
2. 遮蔽sigalrm訊號,讓該訊號處於未決狀態,直接解除對該訊號的遮蔽
3. 呼叫alarm()
設定鬧鐘
4. 呼叫sigsuspend( )
臨時解除型號,並掛起等待執行完訊號處理函式返回
5. 取消鬧鐘
6. 恢復訊號捕捉
7. 恢復訊號遮蔽
#include
#include
// 什麼事情也不做
利用訊號量機制實現前驅關係
記錄型訊號量 typedef struct semaphore wait semaphore s signal semaphore s s value的初值表示系統中某類資源的數目,可稱為資源訊號量。注 利用記錄型訊號量實現前驅關係 例1 已知a,b的值,表示 a 3b b 5a 求值過程的前趨圖。...
Linux 訊號 模擬實現sleep
1 產生訊號 產生訊號的3種方式 1 呼叫系統函式 kill raise abort 2 軟體異常行為 3 組合鍵 ctrl c ctrl d ctrl 等 處理訊號的3種方式 1 忽略。2 預設 很多情況下是終止 3 自定義 訊號捕捉 訊號在核心中的表示 1 遞達 執行訊號的處理動作稱為訊號遞達 ...
linux訊號 阻塞訊號
1.訊號在核心中的表示 我們知道了訊號產生的各種原因,而實際執行訊號處理的動作,叫做訊號遞達 delivery 訊號從產生到遞達之間的狀態,稱為訊號未決 pending 程序可以選擇阻塞 block 某個訊號。被阻塞的訊號產生時將保持在未決狀態,直到程序解除對此訊號的阻塞,才執行遞達的動作。注意,阻...