1. 程式人生 > >判斷是否在同一個執行緒-GetCurrentThreadId()用法

判斷是否在同一個執行緒-GetCurrentThreadId()用法

執行緒

在一個程式中,這些獨立執行的程式片斷叫作“執行緒”(Thread),利用它程式設計的概念就叫作“多執行緒處理”。利用執行緒,使用者可按下一個按鈕,然後程式會立即作出響應,而不是讓使用者等待程式完成了當前任務以後才開始響應。
判斷是否在同一個執行緒中的根本方法也比較簡單,在Windows上直接用 GetCurrentThreadId() 比較;
GetCurrentThreadId() 會直接輸出執行緒id。

注意:

1.執行緒id是動態分配的,因此如果某一個執行緒結束以後,這個id號還可能會分配給另一個執行緒,所以會有重複。
2.之所以會出現相同ID的情況,可能是以下原因:先前的執行緒已經被銷燬了;採用的是非同步機制;訊息機制;執行緒執行得太短時間了,還沒有等其它執行緒啟動就已經執行完了。
3.直接輸出了GetCurrentThreadID的返回值可能會出現重複的現象,
這個返回值不能直接輸出的,該函式採用的是暫存器返回,很快會被其他操作覆蓋!
正確的做法是:
將GetCurrentThreadID的返回值賦值給一個臨時變數;而後輸出該臨時變數
以前自己將GetCurrentThreadID的值作為map的key,也出了問題,改用臨時變數就解決了。
4.打印出id的那句是:

TRACE("Current Thread ID = 0x%X\n", AfxGetThread()->m_nThreadID);

直接輸出也可以。

一、關於設定斷點和單步執行

很多同學非常依賴於偵錯程式的斷點功能和單步功能。這在單執行緒情況下倒還好(不過有些單執行緒但涉及GUI的程式,也會有點麻煩)。至於多執行緒程式的除錯,這兩種手段簡直就是噩夢的開始。多執行緒造成的主要問題大都和競態條件(Race Condition,詳細解釋看“這裡 ”)有關。

而設定斷點或單步跟蹤可能會嚴重干擾 多執行緒之間的競爭狀態。導致你看到的是一個假象。比如本來有兩個執行緒併發執行,存在某些不和諧的Bug(由競態引起)。一旦你在某一個執行緒設定了斷點,該執行緒在斷點處停住了,只剩下另一個執行緒在跑。這時候,併發的場景已經完全被破壞了,你通過偵錯程式看到的可能 是一個和諧的場景。

稍微跑一下題。這很類似量子力學的“測不準原理”,觀測者的觀測行為干擾了被測量的客體,導致觀測者看到的是一個干擾後的現象。

二、關於Log輸出

既然斷點和單步不好用。那咋辦捏?一個替代方案是輸出log日誌。它可以有效減輕斷點和單步所導致的(針對競態條件的)副作用。

1、傳統Log機制的問題

傳統的log輸出主要是列印到螢幕或者輸出到檔案。對於C++而言,標準庫內建的類和函式(比如cout、printf、fputs)可能會有執行緒安全的問題(和編譯器的具體實現有關)。尤其是標準流類庫(iostream)的八個全域性物件,更是要小心慎用。輕則輸出的log文字混雜,重則導致程式崩潰。

鑑於上述原因,應該儘量使用第三方執行緒庫內建的log機制來搞定log輸出功能。比如ACE內建的ACE_Log_Msg等。

2、Log函式要短小精悍

很多情況下,我們會包裝一個公用的函式來實現log輸出功能。然後在該函式內部呼叫執行緒庫的log類/函式。為了不影響執行緒的競態條件,這個log函式要儘可能簡單輕便:不要涉及太多雜七雜八的瑣事、千萬別進行耗時的操作、儘量不操作一些全域性的變數。

3、Log的副作用

不過捏,即使log函式再短小精悍,也還是有可能影響競態條件(畢竟log也有開銷,也要消耗CPU時間)。

萬一競態條件受到log的影響,那就比較棘手了。我以前就碰到過這種情況:加了log,程式沒有問題;去掉log,程式隨機崩潰。這種情況一般有兩種可能:要麼是log功能本身有問題,要麼是程式的競態條件非常敏感(連log的開銷都會有影響)。

這時候你能依靠的就只有肉眼和人腦了。先把相關的程式碼和文件仔細看上幾遍(最好再找其他有經驗的人一起Code Review),然後大家一起開動腦筋使勁琢磨。

三、關於Debug版本和Release版本

C++程式經常有Debug版本和Release版本的區別。有些時候,這也會導致一些多執行緒的問題。

由於Debug版本包含了一些除錯資訊、啟用了某些除錯機制(比如assert巨集)。所以就可能 影響到多執行緒的競爭狀態。在倒黴的時候,會碰上Debug版本工作正常,Release版本程式隨機崩潰。要避免這種情況,可以考慮下面兩個辦法:

1、放棄使用Debug版本

你可以乾脆放棄使用Debug版本。在這種情況下,你需要考慮把諸如assert之類除錯相關的巨集替換成自己的一套巨集,使得在非Debug版本下也可以生效。

2、兩種版本同步測試

使用此方法,程式設計師平時自測可以使用Debug版本,但是測試人員日常測試的必須是Release版本。具體的操作步驟可以利用每日構建來輔助進行(每日構建的介紹參見“這裡 ”)。一定要避免:在平時僅僅搞Debug版本的測試,等到釋出前夕再製作Release版本。這種做法是非常危險的!