開源庫的選擇和駕馭

開源庫的選擇和駕馭

C/C++的開源庫大部分還是比較好的,體現在:

1、開源,意味着可以使用lib或源碼,這點很靈活。

2、功能現成,意味着我們不需要再重複勞動。

3、一般較符合標準國際,通用性好。

4、一般免費,license較寬鬆,具體見GPL LGPL BSD等license,然而我們是天朝的特殊情況,你懂的。。

然而好的庫,其實未必好用,有很多坑,甚至不明顯,甚至坑很深:

1、即便成熟的庫(尤其是C的),一般都是需要初始化。

例如pjsip裏的pjlib pjutil pjnath等基本都有個xxx_init(),而上來就用或者忘記使用這些init的代碼就會帶來問題。

2、函數功能的坑,比如pj_str_t pj_str(char * str)這個函數,不翻源碼,你能知道這是個淺拷貝函數嗎?

假如你給它傳了個臨時變量的str,那你就給自己挖了個坑,什麼時候掉進去是未知的。

2、異常的崩潰問題,即便你定位到該位置,缺發現原本很正常的代碼卻崩潰了。

註釋掉幾行代碼,發現崩潰延後了,這說明是其他問題引起的堆棧崩潰,而不是該幾行代碼的問題。

而這種問題的解決基本是無跡可尋的,只有個“0x0000005”不可訪問之類的異常。

這樣的問題很可能是該庫或者該接口有依賴:

比如,使用pjlib庫的外部線程必須被註冊給pjlib庫,本人使用pjnath庫就遇到了這樣的問題。

vs2012 編譯的pjnath icedemo例子沒問題,自己改來用在dll裏 結果 出現 堆棧被破壞

#  define PJ_CHECK_STACK()// pj_thread_check_stack(__FILE__, __LINE__)
把該宏空置失效,可以解決,但是百思不得其解。

後來終於發現是外部使用線程並未註冊給pjlib,還是尼瑪翻源碼發現的。

pj_thread_register的說明:

This function must be called in the context of the thread being registered.
 * When the thread is created by external function or API call,
 * it must be 'registered' to PJLIB using pj_thread_register(), so that it can
 * cooperate with PJLIB's framework.

這引起了我的懷疑,在外部線程函數優先調用下邊的函數來嘗試

  1. bool ice_register_thread()  
  2. {  
  3.     if(!pj_thread_is_registered())   
  4.     {  
  5.         pj_thread_desc desc;  
  6.         pj_thread_t* thed;  
  7.         if (pj_thread_register(NULL,desc,&thed) == PJ_SUCCESS)  
  8.         {  
  9.             return true;  
  10.         }  
  11.     }  
  12.     return false;  
  13. }  

原來存在的正常位置代碼堆棧崩潰問題消失了。
這個現象裏是pjnath依賴pjlib和pjutil,而pjlib依賴“調用pjlib庫的外部線程必須註冊給它”這個條件。

而這個條件在pjnath的文檔或wiki裏並未體現,所以有時候要調查清楚所有的依賴問題來定位異常。

3、使用源碼和lib或dll的經常有區別。

比如pthread for win32的版本使用靜態庫的時候,必須使用成對的初始化和銷燬函數。而用dll就沒這問題。

4、跨平臺問題。

越成熟的庫跨平臺性能越好,linux和windows下的編譯和使用文檔健全,用的人多,出了問題,度娘、谷哥一般能解決問題。

最後,談下自己的經驗:

選庫條件:1、出的早2、用的人多3、依賴其他庫少4、各個平臺開發使用文檔詳細5、最好用c++的庫(c庫有些回調函數是滿天飛的)6、能滿足自己需要,其他功能越少越好。

用庫方法:1、涉及的文檔務必仔細看2、遇到問題不要輕易放棄,可選用排除法定位問題類型3、務必多嘗試4、搞不定的,先變通實現最好

最後,駕馭開源庫是一個時間未知的工作,但是我們儘量縮短時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章