本文的主要內容為開發C++多線程應用程式時,有關調試和測試的一些注意事項。下面這些注意事項主要是針對C++,不過有些對於其他語言也適用。
★ 關於設定斷點和逐步執行
很多同學非常依賴於調試器的斷點功能和單步功能,這在單線程的情況下倒還好(不過有些單線程但涉及GUI的程式,也會有點麻煩)。至於多線程程式的調試,這兩種手段簡直就是噩夢的開始。多線程造成的主要問題大都和競態條件(Race Condition)有關。而設定斷點或單步跟蹤可能會嚴重幹擾多線程之間的競爭狀態,導致你看到的是一個假象。比如,本來有兩個線程並發執行,存在某些不和諧的Bug(由競態引起),一旦你在某一個線程設定了斷點,該線程在斷點處停住了,只剩下另一個線程在跑,這時候,並發的情境已經完全被破壞了,你通過調試器看到的可能是一個和諧的情境。
稍微跑一下題,這很類似量子力學的“測不準原理”,觀測者的觀測行為幹擾了被測量的客體,導致觀測者看到的是一個幹擾後的現象。
★ 關於Log輸出
既然斷點和單步不好用,那咋辦捏?一個替代的方案是輸出log日誌,它可以有效減輕斷點和單步所導致的(針對競態條件的)副作用。
◇ 傳統log機制的問題
傳統的log輸出主要是列印到螢幕或者輸出到檔案。對於C++而言,標準內建的類和函數(比如cout、printf、fputs)可能會有安全執行緒的問題(和編譯器的具體實現有關)。尤其是標準流類庫(iostream)的八個全域對象,更是要小心慎用,輕則輸出的log文本混雜,重則導致程式崩潰。
鑒於上述原因,應該盡量使用第三方線程庫內建的log機制來搞定log輸出功能,比如ACE內建的ACE_Log_Msg等。
◇ Log函數要短小精悍
很多情況下,我們會封裝一個公用的函數來實現log輸出功能,然後在該函數內部調用線程庫的log類函數。為了不影響線程的競態條件,這個log函數要儘可能簡單輕便:不要涉及太多雜七雜八的瑣事,千萬別進行耗時的操作、盡量不操作一些全域的變數。
◇ Log的副作用
不過,即使log函數再短小精悍,也還是有可能影響競態條件(畢竟log也有開銷,也要消耗CPU的時間)。
萬一競態條件收到log的影響,那就比較棘手了。我以前就碰到過這種情況:加了log,程式沒有問題;去掉log,程式就隨機崩潰。這種情況一般有兩種可能:要麼log功能本身有問題,要麼是程式的競態條件非常敏感(連log的開銷都會有影響)。
這時候你能依靠的就只有肉眼和人腦了,先把相關的代碼和文檔仔細看上幾遍(最好再找其他有經驗的人一起Code Review),然後大家一起開動腦筋使勁琢磨。
★ 關於Debug版本和Release版本
C++程式經常有Debug版本和Release版本的區別。有些時候,這也會導致一些多線程的問題。
由於Debug版本包含了一些調試資訊、啟用了某些調試機制(比如assert宏),所以就可能影響到多線程的競爭狀態。在倒黴的時候,會碰上Debug版本工作正常,Release版本程式隨機崩潰。要避免這種情況,可以考慮下面兩個辦法:
◇ 放棄使用Debug版本
你可以乾脆放棄使用Debug版本。在這種情況下,你需要考慮把諸如assert之類的調試相關的宏替換成自己的一套宏,使得在非Debug版本下也可以生效。
◇ 兩種版本同步測試
使用此方法,程式員平時自測時可以使用Debug版本,但是測試人員日常測試的必須是Release版本。具體的操作步驟可以利用每日構建來輔助進行。一定要避免:在平時僅僅搞Debug版本的測試,等到發布前夕再製作Release版本。這種做法是非常危險的!
★ 關於測試的機器(硬體)
說一個親身經曆、印象深刻的事情。
當年用ACE開發跨平台程式的時候,公司內的開發環境和測試環境都是單CPU的機器。因為當時多核的機器還沒有面世,多CPU的機器又挺貴,公司沒捨得花錢配置。軟體開發完之後,測試人員經過幾輪迴歸測試,也沒發現太大問題,但是拿到客戶的環境中運行,卻經常會隨機性崩潰。因為不能在客戶的環境中Debug,自己的環境又死活沒問題,開發組的幾個人只好充分發揮肉眼和人腦的功能(盯著代碼和設計文檔猛想),經過N長時間,差點把腦子想破,最後才意識到客戶的機器是多CPU的,然後趕緊從其他部門接了一台多CPU機器,裝上軟體調試,最後查出是一個第三方庫有問題。此事過後,我立即想出各種法子,去申請了幾台多CPU的機器給測試人員用。
由於上述的前車之鑒,所以我強烈建議:如果是開發多線程的應用程式,盡量給每一個編程人員和測試人員都配置多核/多CPU的機器,畢竟現在多核機器已經很普及了,即使多CPU的機器,價格也還湊合,實在沒有必要為了省那點小錢而引入開發風險(不光會浪費開發/測試人員的時間,還可能增加實施和維護的成本)。
有同學可能會問“超執行緒的機器如何捏?”,關於多CPU、多核、超執行緒三者之間的差異,有興趣的同學可以看“這裡”,我個人感覺超執行緒不如多核與多CPU爽。
本文出處:http://hi.baidu.com/epeak/blog/item/72c2104e3d1f31c2d1c86ab5.html