共用方式為


開始偵錯多線程應用程式 (C#、Visual Basic、C++)

Visual Studio 提供數個工具和使用者介面元素,可協助您偵錯多線程應用程式。 本教學課程示範如何使用線程標記、 平行堆疊 視窗、 平行監看 式視窗、條件斷點和篩選斷點。 完成本教學課程可讓您熟悉 Visual Studio 功能,以偵錯多線程應用程式。

這兩篇文章提供有關使用其他多線程偵錯工具的其他資訊:

第一個步驟是建立多線程應用程式專案。

建立多線程應用程式專案

  1. 開啟 Visual Studio 並建立新的專案。

    如果啟動視窗未開啟,請選擇 [ 檔案>開始視窗]。

    在 [開始] 視窗中,選擇 [建立新專案]。

    在 [ 建立新專案 ] 視窗中,於搜尋方塊中輸入或輸入 控制台 。 接下來,從 [語言] 列表中選擇 [C#]、 [C++] 或 [Visual Basic ],然後從 [平臺] 清單中選擇 [Windows ]。

    套用語言和平臺篩選之後,請選擇 .NET 或 C++ 的 控制台應用程式 範本,然後選擇 [ 下一步]。

    備註

    如果您沒有看到正確的範本,請移至 [工具>取得工具和功能...],這會開啟Visual Studio安裝程式。 選擇 .NET 桌面開發 或使用 C++ 工作負載進行 桌面開發 ,然後選擇 [修改]。

    在 [設定新的專案] 視窗中,在 [專案名稱] 方塊中輸入或輸入 MyThreadWalkthroughApp。 然後,選擇 [ 下一步 ] 或 [ 建立],無論哪一個選項都可以使用。

    針對 .NET Core 或 .NET 5+ 專案,選擇建議的目標 Framework 或 .NET 8,然後選擇 [ 建立]。

    新的主控台專案隨即出現。 建立項目之後,就會顯示原始程序檔。 視您選擇的語言而定,原始程序檔可能會呼叫 Program.csMyThreadWalkthroughApp.cppModule1.vb

  2. 刪除出現在原始程式檔中的程式代碼,並將它取代為下列更新的程序代碼。 為您的程式代碼組態選擇適當的代碼段。

    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.");
    
        }
    }
    
  3. 在 [File] \(檔案\) 功能表上,選取 [Save All] \(全部儲存\)

  4. (僅限 Visual Basic)在 [方案總管] (右窗格) 中,以滑鼠右鍵按兩下項目節點,選擇 [ 屬性]。 在 [ 應用程式] 索引標籤下,將 Startup 物件 變更為 Simple

對多線程應用程式進行偵錯

  1. 在原始碼編輯器中,尋找下列代碼段:

    Thread.Sleep(3000);
    Console.WriteLine();
    
  2. Thread.Sleep 或 C++ 的 std::this_thread::sleep_for 語句旁的左側空白區按一下滑鼠左鍵以插入新的斷點。

    在排水溝中,紅色圓圈表示此位置已設定斷點。

  3. 在 [ 偵錯] 功能表上,選取 [ 開始偵錯 ] (F5)。

    Visual Studio 會建置解決方案,應用程式會以附加的調試程式開始執行,然後應用程式會在斷點停止。

  4. 在原始碼編輯器中,找出包含斷點的行。

探索線程標記

  1. 在 [偵錯工具列] 中,選取 [在原始碼中顯示執行緒] 按鈕 在原始碼中顯示執行緒執行緒標記]。

  2. F11 兩次以推進調試程式。

  3. 查看視窗左側的排水溝。 在此行中,請注意 線程標記 圖示 線程標記 ,類似於兩個扭曲的線程。 線程標記表示線程已在此位置停止。

    線程標記可以部分隱藏於斷點。

  4. 將指標懸停在主題標記上。 此時會出現一個 DataTip,告訴您每個已停止線程的名稱和線程標識碼。 在這裡情況下,名稱可能是 <noname>

    DataTip 中線程標識碼的螢幕快照。

  5. 選取線程標記以查看快捷方式功能表上的可用選項。

檢視線程位置

在 [ 平行堆棧 ] 視窗中,您可以在 [線程] 檢視和 [工作型程序設計] 工作檢視之間切換,而且您可以檢視每個線程的呼叫堆棧資訊。 在此應用程式中,我們可以使用 [線程] 檢視。

  1. 通過選擇偵錯>>來開啟平行堆疊視窗。 您應該會看到類似以下的畫面。 確切的資訊可能會因每個線程、硬體和程式設計語言的目前位置而有所不同。

    平行堆疊視窗的螢幕快照。

    在此範例中,從左至右顯示受管理的程式碼資訊:

    • 目前線程 (黃色箭號) 已輸入 ServerClass.InstanceMethod。 您可以將滑鼠停留在 上 ServerClass.InstanceMethod,以檢視線程的線程標識碼和堆疊框架。
    • Thread 31724 等候 Thread 20272 的鎖。
    • 主線程(左側)已停止於[外部程式碼],如果您選擇顯示外部程式碼,您可以查看詳細資訊。

    平行堆疊視窗

    在此範例中,從左至右顯示受管理的程式碼資訊:

    • 主線程(左側)已停止在Thread.Start,停止點由線程標記圖示 Thread Marker識別。
    • 兩個線程已進入 ServerClass.InstanceMethod,其中一個是當前線程(黃色箭號),而另一個線程已在 Thread.Sleep 停止。
    • 一個新的線程(在右側)也正在啟動,但已在 ThreadHelper.ThreadStart 停止。
  2. 若要在清單檢視中檢視執行緒,請選取 [ 偵錯>Windows>執行緒]。

    線程視窗的螢幕快照。

    在這裡檢視中,您可以輕鬆地看到線程 20272 是主要線程,目前位於外部程式代碼中,特別是 System.Console.dll

    備註

    如需有關使用 執行緒 視窗的詳細資訊,請參閱 指南:偵錯多執行緒應用程式

  3. 以滑鼠右鍵按兩下 [平行堆疊 ] 或 [ 線程 ] 視窗中的專案,以查看快捷方式功能表上的可用選項。

    您可以從這些右鍵功能表採取各種動作。 在本教學課程中,您會在 [平行監看 式] 視窗中探索更多詳細數據(下一節)。

在變數上設置監視

  1. 以開啟 平行監看 視窗,請選取偵錯>Windows>平行監看>平行監看 1

  2. 選擇您在其中看到 <Add Watch> 文字的儲存格(或第四欄中的空白標題儲存格),然後輸入 data

    每個線程的數據變數值會出現在視窗中。

  3. 選擇您看到 <Add Watch> 文字的儲存格(或第五欄中的空白標題儲存格),然後輸入 count

    每個線程的 count 變數值會出現在視窗中。 如果您還沒看到太多資訊,請嘗試按 F11 幾次,以在調試程式中推進線程的執行。

    平行監看式視窗

  4. 以滑鼠右鍵按下視窗中的其中一個數據列,以查看可用的選項。

標記和取消標記線程

您可以標記線程以追蹤重要的線程,並忽略其他線程。

  1. 在 [ 平行監看 式] 視窗中,按住 Shift 鍵並選取多個數據列。

  2. 以滑鼠右鍵按下並選取 [旗標]。

    所有選取的線程都會加上旗標。 現在,您可以篩選只顯示已標記的主題。

  3. [平行監看] 視窗中,選取 [只顯示標幟的線程] 按鈕 [顯示已標幟的線程]

    清單中只會顯示已標記的主題。

    小提示

    在標記某些執行緒後,您可以在程式碼編輯器中以滑鼠右鍵按一下程式碼行,然後選擇 執行標記的執行緒至游標。 請務必選擇所有標記線程都會到達的代碼。 Visual Studio 會在選取的程式代碼行上暫停線程,藉由 凍結和解除凍結線程,更輕鬆地控制執行順序。

  4. 再次選取 [ 僅顯示標幟的線程 ] 按鈕,切換回 [顯示所有線程 ] 模式。

  5. 若要取消標記線程,請在 平行監看 視窗中,以滑鼠右鍵點擊一或多個已標記的線程,然後選取 取消旗標

凍結和解除凍結線程執行

小提示

您可以凍結和解除凍結 (暫停和繼續) 線程,以控制線程執行工作的順序。 這可協助您解決並行問題,例如死結和競爭條件。

  1. 平行監看 視窗中,選取所有行,然後右鍵點擊選擇 凍結

    在第二個數據行中,每個數據列都會顯示暫停圖示。 暫停圖示表示線程已凍結。

  2. 只選取一個數據列,以取消選取所有其他數據列。

  3. 以滑鼠右鍵按兩下數據列,然後選取 [解除凍結]。

    暫停圖示會消失在這個數據列上,這表示線程不再凍結。

  4. 切換至程式代碼編輯器,然後按 F11。 只會執行未凍結的線程。

    應用程式也可能具現化一些新的線程。 任何新的線程都未加上旗標,且不會凍結。

遵循具有條件斷點的單一線程

在偵錯中跟踪單一線程的執行會很有幫助。 其中一種方法是凍結您不感興趣的討論串。 在某些情況下,您可能需要追蹤單個執行緒而不凍結其他執行緒,例如重現特定的錯誤。 若要追蹤線程而不凍結其他線程,您必須避免進入除您關心的線程之外的代碼。 您可以藉由設定 條件斷點來執行這項工作。

您可以在不同的條件下設定斷點,例如線程名稱或線程標識碼。 在資料上設定您知道對每個線程而言都是獨一無二的條件,這可能會很有幫助。 當您對某些特定數據值比任何特定線程更感興趣時,此方法在偵錯期間很常見。

  1. 以滑鼠右鍵按下您先前建立的斷點,然後選取 [ 條件]。

  2. 在 [ 斷點設定] 視窗中,輸入 data == 5 條件表達式。

    條件斷點

    小提示

    如果您對特定線程更感興趣,請針對條件使用線程名稱或線程標識碼。 若要在 [ 斷點設定] 視窗中執行這項作,請選取 [篩選 ] 而不是 [ 條件表達式],然後遵循篩選提示。 您可能會想要在應用程式程式代碼中 為線程命名 ,因為當您重新啟動調試程式時,線程標識碼變更。

  3. 關閉 [斷點設定] 視窗。

  4. 選取 [重新啟動應用程式] 按鈕,以重新啟動偵錯會話。

    您會在資料變數值為 5 的線程上中斷程式代碼。 在 [ 平行監看 式] 視窗中,尋找指出目前調試程序內容的黃色箭號。

  5. 現在,您可以使用 F10 來跳過程式碼,使用 F11 來進入程式碼,並遵循單一線程的執行。

    只要斷點條件對線程而言是唯一的,而且調試程式不會在其他線程上叫用任何其他斷點(您可能需要停用它們),您就可以逐步執行程式碼並逐步執行程式代碼,而不切換至其他線程。

    備註

    當您推進除錯工具時,所有執行緒都會運行。 不過,調試程式不會中斷其他執行緒的代碼,除非其他執行緒之一到達了斷點。