天天看點

《UNIX環境進階程式設計(第3版)》——1.7 出錯處理

本節書摘來自異步社群《unix環境進階程式設計(第3版)》一書中的第1章,第1.7節,作者:【美】w. richard stevens , stephen a.rago著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

當unix系統函數出錯時,通常會傳回一個負值,而且整型變量errno通常被設定為具有特定資訊的值。例如,open函數如果成功執行則傳回一個非負檔案描述符,如出錯則傳回1。在open出錯時,有大約15種不同的errno值(檔案不存在、權限問題等)。而有些函數對于出錯則使用另一種約定而不是傳回負值。例如,大多數傳回指向對象指針的函數,在出錯時會傳回一個null指針。

檔案中定義了errno以及可以賦與它的各種常量。這些常量都以字元e開頭。另外,unix系統手冊第2部分的第1頁,intro(2)列出了所有這些出錯常量。例如,若errno等于常量eacces,表示産生了權限問題(例如,沒有足夠的權限打開請求檔案)。

在linux中,出錯常量在errno(3)手冊頁中列出。

posix和iso c将errno定義為一個符号,它擴充成為一個可修改的整形左值(lvalue)。它可以是一個包含出錯編号的整數,也可以是一個傳回出錯編号指針的函數。以前使用的定義是:

<code>extern int errno;</code>

但是在支援線程的環境中,多個線程共享程序位址空間,每個線程都有屬于它自己的局部errno以避免一個線程幹擾另一個線程。例如,linux支援多線程存取errno,将其定義為:

對于errno應當注意兩條規則。第一條規則是:如果沒有出錯,其值不會被例程清除。是以,僅當函數的傳回值指明出錯時,才檢驗其值。第二條規則是:任何函數都不會将errno值設定為0,而且在中定義的所有常量都不為0。

c标準定義了兩個函數,它們用于列印出錯資訊。

strerror函數将errnum(通常就是errno值)映射為一個出錯消息字元串,并且傳回此字元串的指針。

perror函數基于errno的目前值,在标準錯誤上産生一條出錯消息,然後傳回。

它首先輸出由msg指向的字元串,然後是一個冒号,一個空格,接着是對應于errno值的出錯消息,最後是一個換行符。

執行個體

圖1-8程式顯示了這兩個出錯函數的使用方法。

圖1-8 例示strerror和perror

如果将此程式編譯成檔案a.out,然後執行它,則有

注意,我們将程式名(argv[0],其值是./a.out)作為參數傳遞給perror。這是一個标準的unix慣例。使用這種方法,在程式作為管道的一部分執行時,例如:

<code>prog1 &lt; inputfile | prog2 | prog3 &gt; outputfile</code>

我們就能厘清3個程式中的哪一個産生了一條特定的出錯消息。

本書中的所有執行個體基本上都不直接調用strerror或perror,而是使用附錄b中的出錯函數。該附錄中的出錯函數使我們隻用一條c語句就可利用iso c的可變參數表功能處理出錯情況。

出錯恢複

可将在中定義的各種出錯分成兩類:緻命性的和非緻命性的。對于緻命性的錯誤,無法執行恢複動作。最多能做的是在使用者螢幕上列印出一條出錯消息或者将一條出錯消息寫入日志檔案中,然後退出。對于非緻命性的出錯,有時可以較妥善地進行處理。大多數非緻命性出錯是暫時的(如資源短缺),當系統中的活動較少時,這種出錯很可能不會發生。

與資源相關的非緻命性出錯包括:eagain、 enfile、 enobufs、 enolck、 enospc、 ewouldblock,有時enomem也是非緻命性出錯。當ebusy指明共享資源正在使用時,也可将它作為非緻命性出錯處理。當eintr中斷一個慢速系統調用時,可将它作為非緻命性出錯處理(在10.5節對此會進行更多說明)。

對于資源相關的非緻命性出錯的典型恢複操作是延遲一段時間,然後重試。這種技術可應用于其他情況。例如,假設出錯表明一個網絡連接配接不再起作用,那麼應用程式可以采用這種方法,在短時間延遲後,嘗試重建該連接配接。一些應用使用指數補償算法,在每次疊代中等待更長時間。

最終,由應用的開發者決定在哪些情況下應用程式可以從出錯中恢複。如果能夠采用一種合理的恢複政策,那麼可以避免應用程式異常終止,進而就能改善應用程式的健壯性。

繼續閱讀