Share via


開始對多執行緒應用程式進行偵錯 (C#、Visual Basic、C++)

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

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

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

建立多執行緒應用程式專案

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

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

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

    在 [建立新專案] 視窗的搜尋方塊中輸入或鍵入 ASP.NET。 接下來,從語言清單中選擇 C#C++Visual Basic,然後從平台清單中選擇 Windows

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

    注意

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

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

    對於 .NET Core 或 .NET 5+ 專案,請選擇建議的目標框架或 .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 中執行緒 ID 的螢幕擷取畫面。

  5. 選取執行緒標記以查看捷徑功能表上的可用選項。

檢視執行緒位置

在 [平行堆疊] 視窗中,您可以在 [執行緒] 檢視和 (針對工作型程式設計) [工作] 檢視之間切換,且您可以檢視每個執行緒的呼叫堆疊資訊。 在此應用程式中,我們可以使用 [執行緒] 檢視。

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

    平行堆疊視窗的螢幕擷取畫面。

    在此範例中,從左至右,我們會看到受控程式碼的這項資訊:

    • 目前執行緒 (黃色箭號) 已輸入 ServerClass.InstanceMethod。 您可以將滑鼠停留在 ServerClass.InstanceMethod 上,以檢視執行緒的執行緒識別碼和堆疊框架。
    • 執行緒 31724 正在等候執行緒 20272 所擁有的鎖定。
    • 主執行緒 (左側) 已在 [外部程式碼] 停止,如果您選擇 [顯示外部程式碼],您可以詳細檢視此執行緒。

    [平行堆疊] 視窗

    在此範例中,從左至右,我們會看到受控程式碼的這項資訊:

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

    [執行緒] 視窗的螢幕擷取畫面。

    在此檢視中,您可以輕鬆地看到執行緒 20272 是主要執行緒,且目前位於外部程式碼中,特別是 System.Console.dll

    注意

    如需關於使用 [執行緒] 視窗的詳細資訊,請參閱逐步解說:偵錯多執行緒應用程式

  3. 以滑鼠右鍵按一下 [平行堆疊] 或 [執行緒] 視窗中的項目,以查看捷徑功能表上的可用選項。

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

在變數上設定監看式

  1. 選取偵錯>視窗>平行監看式>平行監看式 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

    有條件的中斷點

    提示

    如果您較需要特定執行緒,請針對條件使用執行緒名稱或執行緒識別碼。 若要在 [中斷點設定] 視窗中執行這項操作,請選取 [篩選] 而不是 [條件運算式],然後遵循篩選提示。 您可能需要在應用程式程式碼中為執行緒命名,因為當您重新啟動偵錯工具時,執行緒 ID 會變更。

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

  4. 選取 [重新啟動] 重新啟動應用程式 按鈕,以重新啟動偵錯工作階段。

    您會在資料變數值為 5 的執行緒上中斷程式碼。 在 [平行監看式] 視窗中,尋找指出目前偵錯工具內容的黃色箭號。

  5. 現在,您可以逐步執行 (step over) 程式碼 (F10) 並逐步執行 (step into) 程式碼 (F11),然後遵循單一執行緒的執行。

    只要中斷點條件對執行緒而言是唯一的,且偵錯工具不會在其他執行緒上叫用任何其他中斷點 (您可能需要加以停用),您就可以逐步執行 (step over) 程式碼並逐步執行 (step into) 程式碼,而不切換至其他執行緒。

    注意

    當您將偵錯工具前移時,所有執行緒都會執行。 不過,除非其中一個其他執行緒叫用中斷點,否則偵錯工具不會在其他執行緒上中斷程式碼。