訊號之可重入函式、競態條件
阿新 • • 發佈:2019-01-11
一、可重入函式
1.基本概念
當捕捉到訊號時,不論程序的主控制流程當前執行到哪兒,都會先跳到訊號處理函式中執行,從 訊號處理函式返回後再繼續執行主控制流程。訊號處理函式是一個單獨的控制流程,因為它 和主控制流程是非同步的,二者不存在調⽤用和被調⽤用的關係,並且使用不同的堆疊空間。引入了 訊號處理函式使得一個程序具有多個控制流程,如果這些控制流程訪問相同的全域性資源(全域性 變數、硬體資源等),就有可能出現衝突。 函式被不同的控制流程呼叫,有可能在第一次呼叫還沒返回時就再次 進入該函 數,這稱為重入,insert函式訪問一個全域性連結串列,有可能因為重入而造成錯亂,像這樣 的函式稱為 不可重入函式,反之,如果一個函式只訪問自己的區域性變數或引數,則稱為可重入 (Reentrant) 函式。 對於不可重入函式: 1.呼叫了malloc或free 2.呼叫了標準I/O庫函式 2.可重入函式與執行緒安全- 不保護共享變數的函式;
- 函式狀態隨著呼叫改變的函式;
- 返回指向靜態變數指標的函式;
- 呼叫執行緒不安全函式的函式
可重入函式要解決的問題是,不在函式內部使用靜態或全域性資料,不返回靜態或全域性資料,也不呼叫不可重入函式。
執行緒安全函式要解決的問題是,多個執行緒呼叫函式時訪問資源衝突。
在上面自己定義的my_sleep函式中,如果鬧鐘剛設定完畢程序被切出去,作業系統發出鬧鐘訊號後進程才被切進來繼續,這樣pause函式執行則不能接收到alarm訊號 這個問題的根本原因是系統執行的時序問題。雖然alarm緊接著下面就是pause,但是還是無法保證pause函式一定會呼叫alarm設定時間內呼叫。 像這類由於時序問題導致的錯誤,叫做競態條件。 sigsuspend解決了竟態條件的問題,它能夠使“解除訊號遮蔽”和“掛起等待訊號”合併成一個原子操作。所以在對時序要求嚴格的場合下都應該呼叫sigsuspend而不是pause
調⽤用sigsuspend時,程序的訊號遮蔽字由sigmask引數指定,可以通過指定sigmask來臨時 解除對某 個訊號的遮蔽,然後掛起等待,當sigsuspend返回時,程序的訊號遮蔽字恢復為原 來的值,如果原來對該訊號是遮蔽的,從sigsuspend返回後仍然是遮蔽的。 三、SIGCHILD訊號 子程序在終止時會給父程序傳送SIGCHILD訊號,該訊號的預設處理動作是忽略,父程序可以自定義SIGCHILD函式。子程序在終止時會通知父程序,父程序在訊號處理函式中呼叫wait清理子程序