?? foundvcerror.htm
字號:
<html>
<head>
<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何定位程序占用CPU100%和掛起兩種錯誤的代碼出錯位置---</title>
</head>
<body>
<p align="center"><b>如何定位程序占用CPU100%和掛起兩種錯誤的代碼出錯位置------VC編程相關</b></p>
<p align="center"><b><a href="DemoDebug.rar">演示代碼</a></b></p>
<p align="left"> <font color="#0000FF"><b>序言</b></font>:筆者是一個使用VC作為開發(fā)工具的程序員,在幾年的
機房監(jiān)控 和 系統(tǒng)集成開發(fā) 程序調試中,開創(chuàng)了一套錯誤定位的調試方法,因為此方法在我6年工作后的今天才創(chuàng)作出來,想必這個創(chuàng)作對很多小弟小妹們都有用,不可獨享,就特拿來和大家分享。希望對大家有益。
機房監(jiān)控系統(tǒng)開放源代碼。</p>
<p align="left">
對于常規(guī)一些錯誤,使用調試模式調試,通常VC會檢查到錯誤的位置,彈出錯誤終止框,根據(jù)VC的錯誤提示可以很快的定位錯誤代碼的位置。然而對于程序運行過程中無故變成CPU占用100%后無響應,或者CPU正常,而程序無故變成無響應狀態(tài),對應兩種錯誤,對于筆者以前的編程日子里,是一個很頭痛的事情,很難定位,特別是程序的代碼很多并且設計多個模塊的情況時,更是難弄。然而,現(xiàn)在,筆者見到此類問題,能很快有效地找到問題的所致。</p>
<p align="left">
為了說明如何定位這兩種錯誤的發(fā)生位置,這里我們提供了一個簡單的演示程序,演示程序中給出了兩個按鈕,一個按鈕按下后不久,程序即進入無響應狀態(tài)(CPU正常),另外一個按鈕則是點擊后不久程序CPU占用幾乎100%,程序無響應。為了更逼真,接近我們日常的調試的難度,演示程序中特將出錯位置代碼與點擊按鈕動作代碼做了簡單的分離。幾個按鈕只是簡單修改一個整型變量的值,而在主框架的OnTimer中根據(jù)這個變量的值的不同做不同的處理,引發(fā)程序掛起:</p>
<p align="left">void CMainFrame::OnTimer(UINT nIDEvent) <br>
{<br>
// TODO: Add your message handler code here
and/or call default<br>
if(m_nChoice == 1)<br>
{<br>
LockToUnresponse();<br>
}<br>
else if(m_nChoice == 2)<br>
{<br>
LoopCPU100();<br>
}<br>
CMDIFrameWnd::OnTimer(nIDEvent);<br>
}<br>
</p>
<p align="left"> <b><font color="#0000FF">補充說明</font></b>:關于演示程序,需要說明的是,這個演示程序只是為了說明如何定位錯誤的問題,因此不是一個完整的程序,程序的某些代碼不具有實際意義,一些變量和線程的初始化和釋放代碼不一定完全,因此,請讀者不要仿效該演示程序代碼的編碼風格。</p>
<p align="left"> <b><font color="#0000FF">現(xiàn)象先睹</font></b>:在說明如何定位錯誤前,我們先來看看這個演示程序的運行效果:</p>
<p align="left"><img border="0" src="FoundV1.jpg"></p>
<p align="left">
點“掛起測試”或“CPU100%測試”按鈕后,程序在3秒后及進入無響應狀態(tài),點前一按鈕后的掛起與點后一按鈕的掛起區(qū)別在于后一種方式掛起后系統(tǒng)的CPU占用馬上上去了。掛起后程序無法接受鼠標和鍵盤的輸入,對話框變白,無法刷新。</p>
<p align="left"> <b><font color="#0000FF">如何定位</font></b>:原理:程序沒有響應,說明一個問題,主線程正忙或者被掛起,因此我們就是要定位主線程在無響應時已經(jīng)執(zhí)行到哪里了。</p>
<p align="left">
對于這兩種情況的無響應的調試錯誤定位方法是相同的,首先我們使用按快捷鍵“F10”單步調試的方式啟動待調試的程序,我們這里即指DemoDebug這個程序,注意,這里我們只按一下“F10”,程序即會停止在如下的程序位置:</p>
<p align="left"><img border="0" src="FoundV2.jpg" width="933" height="742"></p>
<p align="left">
對于所有的程序,按“F10”后都是停在這個地方,此時按VC的菜單“Debug->Threads”:</p>
<p align="left"><img border="0" src="FoundV4.jpg"></p>
<p align="left"> 線程列表中,目前只有一個線程,這個就是主線程,記下這個線程的ID,這里是00000f6c。</p>
<p align="left">
然后按“F5”繼續(xù)調試運行,程序開始時是有響應的,點測試按鈕以外的其他按鈕、以及菜單都是有響應的:</p>
<p align="left"><img border="0" src="FoundV5.jpg"></p>
<p align="left"> 此時我們點兩個測試按鈕中的任意一個,程序在3秒后即變得無響應了:</p>
<p align="left"><img border="0" src="FoundV1.jpg"></p>
<p align="left"> 此時切換到VC,點VC的菜單“Debug->Break”,暫停程序運行:</p>
<p align="left"><img border="0" src="FoundV6.jpg" width="987" height="768"></p>
<p align="left">
暫停后,Debug下的Threads菜單變成可點擊的黑色,點Threads,再次進入線程列表對話框:</p>
<p align="left"><img border="0" src="FoundV7.jpg"></p>
<p align="left"> 找到我們在上面已經(jīng)記下的Thread
ID值00000f6c,找到這一行后鼠標雙擊這一行,VC即切換到該主線程的當前運行位置:</p>
<p align="left"><img border="0" src="FoundV8.jpg"></p>
<p align="left"><img border="0" src="FoundV9.jpg"></p>
<p align="left"> 在運行堆棧中,我們看到,有我們的自己寫的代碼段在堆棧中,雙擊“CMainFrame::LockToUnresponse()”所在的行,VC的上面代碼框中將切換到CMainFrame::LockToUnresponse()函數(shù)的聲明位置,這里我就可以看到在主線程中的OnTimer中常識鎖定
m_mutexSingleWay,而該互斥鎖正被另外一個線程CMainFrame::AnyThreadLoop(LPVOID lParam)鎖定(或占用),所以主線程被掛起,這樣,錯誤的位置就被這樣找到了。接下來如何處理出錯代碼的問題已經(jīng)超出了本文想講的問題,在這里不再往下說明。</p>
<p align="left"> CPU
占用100%的問題的查找方法是一樣的,先按“F10”的方式開始調試運行該程序,記下主線程的Thread ID,再按“F5”啟動程序,點“CPU
100%測試”按鈕,等程序沒有響應后,點VC的菜單“Debug->Break”暫停程序,再點“Debug->Threads”,列出所有線程,根據(jù)記下的線程ID,找到主線程,雙擊該主線程行,VC此時切換到CPU
占用100%的線程的堆棧:</p>
<p align="left"><img border="0" src="FoundV10.jpg"></p>
<p align="left"> </p>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -