2014-02-26 54 views
6

我正在閱讀「UNIX系統編程」一書,並介紹了以下幾點。爲什麼如果出現任何信號,C庫函數就會失敗

無論何時調用C庫函數(例如close()),最好檢查EINTR錯誤代碼,因爲如果進程收到任何信號,庫函數可能會失敗。如果發生了EINTR錯誤,則應重新啓動相應的C庫調用。

while ((close(fd) == -1) && errno == EINTR); // close is restarted if it fails with EINTR error. 

問題:爲什麼庫函數在獲取信號時會失敗? 收到信號後,調用相應的處理程序。處理程序完成後,庫函數不能從它停止的位置繼續?

+1

在UNIX Hater's Handbook中,有一個軼事應該根據它來判斷,但是UNIX和相關標準的制定者卻選擇將它轉儲到用戶的膝上,因爲它使操作系統更易於實現。 – Medinoc

+0

注意:close()不是一個庫函數,而是一個(包裝)系統調用。系統調用可能會失敗。 (由於爭議不佳,資源短缺,(假設)種族/衝突,......)自動重啓並不總是一種選擇,在某些情況下,主叫方應該自行採取行動。 – wildplasser

回答

7

爲什麼庫函數在獲取Signal時會失敗?

因爲這是它是如何設計的,我們的目標是,如果一個信號到達 當你被困在一個阻塞系統調用,系統調用返回,和你有 機會採取行動的信號。

但是,傳統上,這在不同的平臺上以許多變體實現。

處理程序完成後,庫函數能否繼續運行?

絕對。如果你想要這種行爲,當你安裝一個sigaction()的信號處理程序時,你可以設置SA_RESTART標誌。

請注意,即使使用SA_RESTART標誌,仍有一些系統調用不會自動重新啓動。對於Linux,您可以在signal(7)手冊頁中看到「信號處理程序中的系統調用和庫函數中斷」中的哪些調用列表。 (如果有人知道由posix定義的類似列表,我會很感激)。

如果您使用signal()而不是sigaction()安裝信號處理程序,它在不同系統調用是否自動重新啓動時會有所不同。 SySV衍生平臺通常不會重新啓動系統調用,而BSD dervied平臺則可以。

而((接近(FD)== - 1)& &錯誤號== EINTR); //如果EINTR錯誤失敗,則關閉將重新啓動。

這實際上是相當危險的。如果close()在EINTR失敗時,文件描述符的狀態是未知的,這意味着如果文件描述符真的關閉了,那麼就有可能導致競爭條件關閉另一個不相關的文件描述符。這在posix規範中被認爲是bug

+0

關於'close'的更多信息,另見http://stackoverflow.com/a/14431867。 – tne

相關問題