Visual Studio 提供數個工具和使用者介面元素,可協助您偵錯多線程應用程式。 本教學課程示範如何使用線程標記、 平行堆疊 視窗、 平行監看 式視窗、條件斷點和篩選斷點。 完成本教學課程可讓您熟悉 Visual Studio 功能,以偵錯多線程應用程式。
這兩篇文章提供有關使用其他多線程偵錯工具的其他資訊:
若要使用 [ 偵錯位置 ] 工具列和 [ 線程] 視窗,請參閱 逐步解說:偵錯多線程應用程式。
如需使用 Task(Managed 原始程式碼)和並行執行階段(C++)的範例,請參閱 逐步解說:對平行應用程式進行偵錯。 如需適用於大部分多線程應用程式類型的一般偵錯秘訣,請閱讀該文章和這篇文章。
第一個步驟是建立多線程應用程式專案。
建立多線程應用程式專案
開啟 Visual Studio 並建立新的專案。
如果啟動視窗未開啟,請選擇 [ 檔案>開始視窗]。
在 [開始] 視窗中,選擇 [建立新專案]。
在 [ 建立新專案 ] 視窗中,於搜尋方塊中輸入或輸入 控制台 。 接下來,從 [語言] 列表中選擇 [C#]、 [C++] 或 [Visual Basic ],然後從 [平臺] 清單中選擇 [Windows ]。
套用語言和平臺篩選之後,請選擇 .NET 或 C++ 的 控制台應用程式 範本,然後選擇 [ 下一步]。
備註
如果您沒有看到正確的範本,請移至 [工具>取得工具和功能...],這會開啟Visual Studio安裝程式。 選擇 .NET 桌面開發 或使用 C++ 工作負載進行 桌面開發 ,然後選擇 [修改]。
在 [設定新的專案] 視窗中,在 [專案名稱] 方塊中輸入或輸入 MyThreadWalkthroughApp。 然後,選擇 [ 下一步 ] 或 [ 建立],無論哪一個選項都可以使用。
針對 .NET Core 或 .NET 5+ 專案,選擇建議的目標 Framework 或 .NET 8,然後選擇 [ 建立]。
新的主控台專案隨即出現。 建立項目之後,就會顯示原始程序檔。 視您選擇的語言而定,原始程序檔可能會呼叫 Program.cs、 MyThreadWalkthroughApp.cpp或 Module1.vb。
刪除出現在原始程式檔中的程式代碼,並將它取代為下列更新的程序代碼。 為您的程式代碼組態選擇適當的代碼段。
using System; using System.Threading; public class ServerClass { static int count = 0; // The method that will be called when the thread is started. public void InstanceMethod() { Console.WriteLine( "ServerClass.InstanceMethod is running on another thread."); int data = count++; // Pause for a moment to provide a delay to make // threads more apparent. Thread.Sleep(3000); Console.WriteLine( "The instance method called by the worker thread has ended. " + data); } } public class Simple { public static void Main() { for (int i = 0; i < 10; i++) { CreateThreads(); } } public static void CreateThreads() { ServerClass serverObject = new ServerClass(); Thread InstanceCaller = new Thread(new ThreadStart(serverObject.InstanceMethod)); // Start the thread. InstanceCaller.Start(); Console.WriteLine("The Main() thread calls this after " + "starting the new InstanceCaller thread."); } }
在 [File] \(檔案\) 功能表上,選取 [Save All] \(全部儲存\)。
(僅限 Visual Basic)在 [方案總管] (右窗格) 中,以滑鼠右鍵按兩下項目節點,選擇 [ 屬性]。 在 [ 應用程式] 索引標籤下,將 Startup 物件 變更為 Simple。
對多線程應用程式進行偵錯
在原始碼編輯器中,尋找下列代碼段:
在
Thread.Sleep
或 C++ 的std::this_thread::sleep_for
語句旁的左側空白區按一下滑鼠左鍵以插入新的斷點。在排水溝中,紅色圓圈表示此位置已設定斷點。
在 [ 偵錯] 功能表上,選取 [ 開始偵錯 ] (F5)。
Visual Studio 會建置解決方案,應用程式會以附加的調試程式開始執行,然後應用程式會在斷點停止。
在原始碼編輯器中,找出包含斷點的行。
探索線程標記
在 [偵錯工具列] 中,選取 [
在原始碼中顯示執行緒] 按鈕 ]。在原始碼中顯示執行緒 執行緒標記 按 F11 兩次以推進調試程式。
查看視窗左側的排水溝。 在此行中,請注意 線程標記 圖示
,類似於兩個扭曲的線程。 線程標記表示線程已在此位置停止。
線程標記可以部分隱藏於斷點。
將指標懸停在主題標記上。 此時會出現一個 DataTip,告訴您每個已停止線程的名稱和線程標識碼。 在這裡情況下,名稱可能是
<noname>
。選取線程標記以查看快捷方式功能表上的可用選項。
檢視線程位置
在 [ 平行堆棧 ] 視窗中,您可以在 [線程] 檢視和 [工作型程序設計] 工作檢視之間切換,而且您可以檢視每個線程的呼叫堆棧資訊。 在此應用程式中,我們可以使用 [線程] 檢視。
通過選擇偵錯>>來開啟平行堆疊視窗。 您應該會看到類似以下的畫面。 確切的資訊可能會因每個線程、硬體和程式設計語言的目前位置而有所不同。
在此範例中,從左至右顯示受管理的程式碼資訊:
- 目前線程 (黃色箭號) 已輸入
ServerClass.InstanceMethod
。 您可以將滑鼠停留在 上ServerClass.InstanceMethod
,以檢視線程的線程標識碼和堆疊框架。 - Thread 31724 等候 Thread 20272 的鎖。
- 主線程(左側)已停止於[外部程式碼],如果您選擇顯示外部程式碼,您可以查看詳細資訊。
在此範例中,從左至右顯示受管理的程式碼資訊:
- 主線程(左側)已停止在
Thread.Start
,停止點由線程標記圖示識別。
- 兩個線程已進入
ServerClass.InstanceMethod
,其中一個是當前線程(黃色箭號),而另一個線程已在Thread.Sleep
停止。 - 一個新的線程(在右側)也正在啟動,但已在
ThreadHelper.ThreadStart
停止。
- 目前線程 (黃色箭號) 已輸入
若要在清單檢視中檢視執行緒,請選取 [ 偵錯>Windows>執行緒]。
在這裡檢視中,您可以輕鬆地看到線程 20272 是主要線程,目前位於外部程式代碼中,特別是 System.Console.dll。
備註
如需有關使用 執行緒 視窗的詳細資訊,請參閱 指南:偵錯多執行緒應用程式。
以滑鼠右鍵按兩下 [平行堆疊 ] 或 [ 線程 ] 視窗中的專案,以查看快捷方式功能表上的可用選項。
您可以從這些右鍵功能表採取各種動作。 在本教學課程中,您會在 [平行監看 式] 視窗中探索更多詳細數據(下一節)。
在變數上設置監視
以開啟 平行監看 視窗,請選取偵錯>Windows>平行監看>平行監看 1。
選擇您在其中看到
<Add Watch>
文字的儲存格(或第四欄中的空白標題儲存格),然後輸入data
。每個線程的數據變數值會出現在視窗中。
選擇您看到
<Add Watch>
文字的儲存格(或第五欄中的空白標題儲存格),然後輸入count
。每個線程的
count
變數值會出現在視窗中。 如果您還沒看到太多資訊,請嘗試按 F11 幾次,以在調試程式中推進線程的執行。以滑鼠右鍵按下視窗中的其中一個數據列,以查看可用的選項。
標記和取消標記線程
您可以標記線程以追蹤重要的線程,並忽略其他線程。
在 [ 平行監看 式] 視窗中,按住 Shift 鍵並選取多個數據列。
以滑鼠右鍵按下並選取 [旗標]。
所有選取的線程都會加上旗標。 現在,您可以篩選只顯示已標記的主題。
在 [平行監看] 視窗中,選取 [只顯示標幟的線程] 按鈕
。
清單中只會顯示已標記的主題。
小提示
在標記某些執行緒後,您可以在程式碼編輯器中以滑鼠右鍵按一下程式碼行,然後選擇 執行標記的執行緒至游標。 請務必選擇所有標記線程都會到達的代碼。 Visual Studio 會在選取的程式代碼行上暫停線程,藉由 凍結和解除凍結線程,更輕鬆地控制執行順序。
再次選取 [ 僅顯示標幟的線程 ] 按鈕,切換回 [顯示所有線程 ] 模式。
若要取消標記線程,請在 平行監看 視窗中,以滑鼠右鍵點擊一或多個已標記的線程,然後選取 取消旗標。
凍結和解除凍結線程執行
小提示
您可以凍結和解除凍結 (暫停和繼續) 線程,以控制線程執行工作的順序。 這可協助您解決並行問題,例如死結和競爭條件。
在 平行監看 視窗中,選取所有行,然後右鍵點擊選擇 凍結。
在第二個數據行中,每個數據列都會顯示暫停圖示。 暫停圖示表示線程已凍結。
只選取一個數據列,以取消選取所有其他數據列。
以滑鼠右鍵按兩下數據列,然後選取 [解除凍結]。
暫停圖示會消失在這個數據列上,這表示線程不再凍結。
切換至程式代碼編輯器,然後按 F11。 只會執行未凍結的線程。
應用程式也可能具現化一些新的線程。 任何新的線程都未加上旗標,且不會凍結。
遵循具有條件斷點的單一線程
在偵錯中跟踪單一線程的執行會很有幫助。 其中一種方法是凍結您不感興趣的討論串。 在某些情況下,您可能需要追蹤單個執行緒而不凍結其他執行緒,例如重現特定的錯誤。 若要追蹤線程而不凍結其他線程,您必須避免進入除您關心的線程之外的代碼。 您可以藉由設定 條件斷點來執行這項工作。
您可以在不同的條件下設定斷點,例如線程名稱或線程標識碼。 在資料上設定您知道對每個線程而言都是獨一無二的條件,這可能會很有幫助。 當您對某些特定數據值比任何特定線程更感興趣時,此方法在偵錯期間很常見。
以滑鼠右鍵按下您先前建立的斷點,然後選取 [ 條件]。
在 [ 斷點設定] 視窗中,輸入
data == 5
條件表達式。小提示
如果您對特定線程更感興趣,請針對條件使用線程名稱或線程標識碼。 若要在 [ 斷點設定] 視窗中執行這項作,請選取 [篩選 ] 而不是 [ 條件表達式],然後遵循篩選提示。 您可能會想要在應用程式程式代碼中 為線程命名 ,因為當您重新啟動調試程式時,線程標識碼變更。
關閉 [斷點設定] 視窗。
選取 [
] 按鈕,以重新啟動偵錯會話。
您會在資料變數值為 5 的線程上中斷程式代碼。 在 [ 平行監看 式] 視窗中,尋找指出目前調試程序內容的黃色箭號。
現在,您可以使用 F10 來跳過程式碼,使用 F11 來進入程式碼,並遵循單一線程的執行。
只要斷點條件對線程而言是唯一的,而且調試程式不會在其他線程上叫用任何其他斷點(您可能需要停用它們),您就可以逐步執行程式碼並逐步執行程式代碼,而不切換至其他線程。
備註
當您推進除錯工具時,所有執行緒都會運行。 不過,調試程式不會中斷其他執行緒的代碼,除非其他執行緒之一到達了斷點。