天天看點

《UNIX網絡程式設計 卷2:程序間通信(第2版)》——1.6 出錯處理:包裹函數

本節書摘來自異步社群《unix網絡程式設計 卷2:程序間通信(第2版)》一書中的第1章,第1.6節,作者:【美】w. richard stevens著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

在現實程式中,我們必須檢查每個函數調用是否傳回錯誤。由于碰到錯誤時終止程式執行是個慣例,是以我們可以通過定義包裹函數(wrapper function)來縮短程式的長度。包裹函數執行實際的函數調用,測試其傳回值,并在碰到錯誤時終止程序。我們使用的命名約定是将函數名第一個字母改為大寫字母,例如:

<code>sem_post(ptr);</code>

圖1-7定義了這個包裹函數。

《UNIX網絡程式設計 卷2:程式間通信(第2版)》——1.6 出錯處理:包裹函數

每當你遇到一個以大寫字母打頭的函數名時,它就是我們所說的包裹函數。它調用一個名字相同但以相應小寫字母開頭的實際函數。當碰到錯誤時,包裹函數總是在輸出一個出錯消息後終止。

我們在講解書中提供的源代碼時,所指代的總是被調用的最低層函數(例如sem_post),而不是包裹函數(例如sem_post)。類似地,書後的索引也總是指代被調用的最低層函數,而不是指代包裹函數。

剛剛展示的源代碼格式全書都在使用。每一非空行都被編号。代碼的正文說明部分的左邊标有起始與結束的行号。有的段落開始處含有一個醒目的簡短标題,概述本段代碼的内容。

源代碼片段起始與結束處的水準劃線标出了該片段所在源代碼檔案名,本例中就是lib目錄下的wrapunix.c檔案。既然本書所有例子的源代碼都可免費獲得(見前言),你就可以憑這個檔案名找到相應的檔案。閱讀本書的過程中,編譯、運作并修改這些程式是學習程序間通信概念的好方法。

盡管包裹函數不見得如何節省代碼量,當在第7章中讨論線程時,我們會發現線程函數出錯時并不設定标準的unix errno變量;相反,本該設定errno的值改由線程函數作為其傳回值傳回調用者。這意味着我們每次調用任意一個線程函數時,都得配置設定一個變量來儲存函數傳回值,然後在調用我們的err_sys函數(圖c-4)前,把errno設定成所儲存的值。為避免源代碼中到處出現花括弧,我們可以使用c語言的逗号運算符,把給errno指派與調用err_sys組合成單個語句,如下所示:

另一種辦法是定義一個新的出錯處理函數,它需要的另一個參數是系統的錯誤号①。但是我們可以将這段代碼簡化得更容易些:

<code>pthread_mutex_lock(&amp;ndone_mutex);</code>

其前提是定義自己的包裹函數,如圖1-8所示。

《UNIX網絡程式設計 卷2:程式間通信(第2版)》——1.6 出錯處理:包裹函數

仔細推敲編碼,我們可改用宏代替函數,進而稍稍提高運作效率,不過即使有過的話,包裹函數也很少是程式性能的瓶頸所在。

選擇将函數名的第一個字母大寫是一種較折中的方法。還有許多其他方法:例如用e作為函數名的字首(如[kernighan and pike 1984]第184頁所示),或者用_e作為函數名的字尾等。同樣提供确實在調用某個其他函數的可視化訓示,我們的方法看來是最少分散人們的注意力的。

這種技巧還有助于檢查那些其錯誤傳回值通常被忽略的函數,例如close和pthread_mutex_lock。

本書後面的例子中我們将普遍使用包裹函數,除非必須檢查某個确定的錯誤并處理它(而不是終止程序)。我們并不給出所有包裹函數的源代碼,但它們是免費可得的(見前言)。

unix errno值

每當在一個unix函數中發生錯誤時,全局變量errno将被設定成一個訓示錯誤類型的正數,函數本身則通常傳回-1。我們的err_sys函數檢查errno的值并輸出相應的出錯消息,例如,errno的值等于eagain時的出錯消息為“resource temporarily unavailable”(資源暫時不可用)。

errno的值隻在某個函數發生錯誤時設定。如果該函數不傳回錯誤,errno的值就無定義。所有正的錯誤值都是常值,具有以e打頭的全部為大寫字母的名字,通常定義在頭檔案中。沒有值為0的錯誤。

在多線程環境中,每個線程必須有自己的errno變量。提供一個局限于線程的errno變量的隐式請求是自動處理的,不過通常需要告訴編譯器所編譯的程式是可重入的。給編譯器指定類似-d_reentrant或-d_posix_c_source=199506l這樣的指令行選項是較典型的方法。頭檔案往往把errno定義成一個宏,當常值_reentrant有定義時,該宏就擴充成一個函數,由它通路errno變量的某個局限于線程的副本。

全書使用類似“mq_send函數傳回emsgsize錯誤”的用語來簡略地表示這樣的意思:該函數傳回一個錯誤(典型情況是傳回值為-1),并且在errno中設定了指定的常值。

繼續閱讀