Linux 利用訊號實現sleep函式

2021-07-31 22:55:35 字數 2679 閱讀 2570

在另一篇文章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 某個訊號。被阻塞的訊號產生時將保持在未決狀態,直到程序解除對此訊號的阻塞,才執行遞達的動作。注意,阻...