教程來自巨頭微軟官方機翻

動手完成全部內容大約需要半小時

完成整個教程的效果圖:(本人使用vs2015 & C++)

vs studio怎麼跑深度學習模型_多線程

正文:

開始調試多線程應用程序 (C#,Visual Basic、 c + +)

Visual Studio 提供多種工具和用户界面元素,用於調試多線程應用程序。 本教程演示如何使用線程標記、“並行堆棧”窗口、“並行監視”窗口、條件斷點、篩選器斷點。 完成本教程只需數分鐘,然後你就會熟悉用於調試多線程應用程序的功能。

下面兩個主題額外介紹瞭如何使用其他多線程調試工具:

若要使用“調試位置”工具欄和“線程”窗口,請參閲演練:調試多線程應用程序。

如需使用 Task(託管代碼)和併發運行時 (C++) 的示例,請參閲演練:調試並行應用程序。 有關適用於大多數多線程應用程序類型的常規調試技巧,請閲讀該主題和本主題。

首先需要一個多線程應用程序項目。 示例如下。

創建一個多線程應用項目

  1. 在“文件”菜單上,選擇“新建” > “項目”。此時將出現“新建項目”對話框。
  2. 選擇語言:Visual C#、Visual C++ 或 Visual Basic。
  3. 在“Windows 桌面”下,選擇“控制枱應用”。
  4. 在“名稱”字段中,輸入 MyThreadWalkthroughApp。
  5. 選擇“確定”。新的控制枱項目隨即顯示。 創建該項目後,將顯示源文件。 根據所選語言,源文件名稱可能是 Program.cs、MyThreadWalkthroughApp.cpp 或 Module1.vb。
  6. 刪除出現在源文件中的代碼,將其替換為下面列出的相應示例代碼。C#
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.");
    }
}

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.");

    }
}

C++

#include "pch.h"
#include <thread>
#include <iostream>
#include <vector>

int count = 0;

void doSomeWork() {

    std::cout << "The doSomeWork function is running on another thread." << std::endl;
    int data = count++;
    // Pause for a moment to provide a delay to make
    // threads more apparent.
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout << "The function called by the worker thread has ended." << std::endl;
}

int main() {
    std::vector<std::thread> threads;

    for (int i = 0; i < 10; ++i) {

        threads.push_back(std::thread(doSomeWork));
        std::cout << "The Main() thread calls this after starting the new thread" << std::endl;
}

for (auto& thread : threads) {
    thread.join();
}

return 0;
}

VB

Imports System.Threading

Public Class ServerClass
    ' The method that will be called when the thread is started.
    Public count = 0
    Public Sub InstanceMethod()
        Console.WriteLine(
                "ServerClass.InstanceMethod is running on another thread.")

        Dim data = count + 1
        ' 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.")
    End Sub

End Class

Public Class Simple

    Public Shared Sub Main()

        Dim ts As New ThreadStarter
        For index = 1 To 10
            ts.CreateThreads()
        Next

    End Sub

End Class
Public Class ThreadStarter
    Public Sub CreateThreads()
        Dim serverObject As New ServerClass()

        ' Create the thread object, passing in the
        ' serverObject.InstanceMethod method using a
        ' ThreadStart delegate.
        Dim InstanceCaller As New Thread(AddressOf serverObject.InstanceMethod)

        ' Start the thread.
        InstanceCaller.Start()

        Console.WriteLine("The Main() thread calls this after " _
                    + "starting the new InstanceCaller thread.")

    End Sub
End Class
  1. 在“文件”菜單上,單擊“全部保存”。
  2. (僅限 Visual Basic)在解決方案資源管理器 (右窗格),右鍵單擊項目節點,選擇屬性。 下應用程序選項卡上,更改啓動對象到簡單。

調試多線程應用程序

  1. 在源代碼編輯器中,查找以下代碼段之一:C#
Thread.Sleep(3000);  
Console.WriteLine();

C++

std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "The function called by the worker thread has ended." << std::endl;

VB

Thread.Sleep(3000)
Console.WriteLine()
  1. 左鍵單擊中的左滾動條槽Thread.Sleep或std::this_thread::sleep_for語句將新斷點。滾動條槽中的紅色圓圈指示在此位置設置斷點。
  2. 在“調試”菜單上,單擊“開始調試(F5)”。Visual Studio 將生成該解決方案,應用在附加了調試器的情況下開始運行,然後在斷點處停止。
  3. 在源代碼編輯器中,找到包含該斷點的行。

發現線程標記  

  1. 在調試工具欄中,單擊“在源中顯示線程”按鈕
  2. vs studio怎麼跑深度學習模型_vs studio怎麼跑深度學習模型_02

  3. 按一下 F11 使調試器前進一個代碼行。
  4. 查看窗口左側的滾動條槽。 在此行中,會看到線程標記 圖標
  5. vs studio怎麼跑深度學習模型_應用程序_03

  6. ,類似於一條雙絞線。 線程標記指示線程在此位置停止。線程標記可以被斷點部分隱藏。
  7. 將指針懸停在線程標記上。 此時會出現一個數據提示,告知你每個已停止線程的名稱和線程 ID 號。 在這種情況下,名稱可能是 <noname>。
  8. 選擇線程標記,以查看快捷菜單上的可用選項。

查看線程位置

在“並行堆棧”窗口中,可以在“線程”視圖和“任務”視圖(適用於基於任務的編程)之間進行切換,並且可以查看每個線程的調用堆棧信息。 在此應用中,我們可以使用“線程”視圖。

  1. 通過選擇“調試” > “窗口” > “並行堆棧”,打開“並行堆棧”窗口。 此時會看到如下所示的內容。 確切信息取決於每個線程的當前位置、硬件以及編程語言。

在此示例中,從左到右會看到託管代碼的以下信息:

  • 主線程(左側)已停止在 Thread.Start 上,由線程標記圖標指示停止點。
  • 兩個線程已進入 ServerClass.InstanceMethod,其中一個線程是當前線程(黃色箭頭),另一個線程已停止在 Thread.Sleep 中。
  • 新線程(右側)也已啓動,但是停止在 ThreadHelper.ThreadStart 上。
  1. 右鍵單擊“並行堆棧”窗口中的條目,查看快捷菜單上的可用選項。可以通過這些右鍵單擊菜單執行各種操作,但在本教程中,我們將在“並行監視”窗口中展示更多這些細節(後續部分)。備註若要查看包含每個線程的信息的列表視圖,請改用“線程”窗口。 請參閲演練:調試多線程應用程序。

對變量設置監視

  1. 通過選擇“調試” > “窗口” > “並行監視” > “並行監視 1”,打開“並行監視”窗口。
  2. 選擇 <Add Watch> 文本所在的單元格(或第 4 列中的空標頭單元格),輸入 data。在窗口中顯示每個線程的數據變量的值。
  3. 選擇 <Add Watch> 文本所在的單元格(或第 5 列中的空標頭單元格),輸入 count。窗口中會顯示每個線程的 count 變量的值。 如果看不到這麼多的信息,請嘗試按 F11 幾次以繼續在調試器中執行線程。
  4. 右鍵單擊其中一個窗口以查看可用選項中的行。

標記線程和取消標記線程

可以通過標記線程來追蹤重要的線程,並忽略其它線程。

  1. 在中並行監視窗口中,按住Shift鍵並選擇多個行。
  2. 右鍵單擊並選擇標誌。所選的所有線程都將都標記。 現在,您可以篩選為僅顯示已標記的線程。
  3. 在中並行監視窗口中,選擇僅顯示標記的線程按鈕。標記的線程顯示在列表中。提示在標記一些線程後,可以右鍵單擊代碼編輯器中的代碼行,然後選擇“將標記的線程運行到光標處”。 請確保選擇所有已標記的線程將達到的代碼。 Visual Studio 將在選擇的代碼行處暫停線程,這樣就可以通過凍結和解凍線程更容易地控制執行順序。
  4. 選擇僅顯示標記的線程按鈕將再次切換回顯示所有線程模式。
  5. 若要取消標記線程,請在“並行監視”窗口右鍵單擊一個或多個已標記線程,然後選擇“取消標記”。

凍結和解凍線程執行

提示

可以通過凍結和解凍(暫停和恢復)線程來控制線程執行工作的順序。 這有助於解決併發問題,例如死鎖和爭用條件。

  1. 在“並行監視”窗口中,在選中所有行的情況下,右鍵單擊並選擇“凍結”。在第二個列中,每個行出現一個暫停圖標。 暫停圖標指示該線程已凍結。
  2. 僅選擇一行,取消選中其他行。
  3. 右鍵單擊某一行,然後選擇解凍。暫停圖標在此行上消失,表明線程已不再被凍結。
  4. 切換到代碼編輯器,按 F11。 僅運行未凍結的線程。應用還實例化某些新線程。 任何新線程均處於未標記狀態,不會被凍結。

請按照具有條件斷點的單一線程

可以在調試器中對單線程的執行情況進行跟蹤。 一種方法是凍結不感興趣的線程。 在某些情況下,可能需要在不凍結其它線程的情況下跟蹤單個線程,例如重現特定 Bug。 若要在不凍結其他線程的情況下跟蹤某個線程,必須避免在不感興趣的線程上中斷。 您可以執行此操作通過設置條件斷點。

可以根據不同的條件(例如,線程名稱或線程 ID)來設置斷點。 如果你知道數據對於每個線程都是唯一的,則可根據該數據設置條件斷點。 這是常見的調試場景,即相比於特定的線程,你對某些特定的數據值更感興趣。

  1. 右鍵單擊以前創建的斷點並選擇條件。
  2. 在“斷點設置”窗口中,輸入 data == 5 作為條件表達式。

提示

如果對特定的線程更感興趣,則請使用線程名稱或線程 ID 作為條件。 若要在“斷點設置”窗口中執行此操作,請選擇“篩選器”而不是“條件表達式”,並按照篩選器提示操作。 可能需要在應用代碼中指定線程名稱,因為線程 ID 在重啓調試器時會更改。

  1. 關閉斷點設置窗口。
  2. 選擇重啓按鈕以重啓調試會話。將在數據變量的值為 5 的線程中,中斷代碼執行。 請在“並行監視”窗口中,尋找表示當前調試器上下文的黃色箭頭。
  3. 現在,可以單步執行代碼 (F10) 和單步執行代碼 (F11) 並按照單個線程執行。只要斷點條件是唯一的線程,且調試器不會命中 (可能需要禁用它們) 的其他線程上的任何其他斷點,可以單步執行代碼並單步執行代碼而無需切換到其他線程。備註當您推進調試器進度時,將運行所有線程。 但是,調試器不會中斷到其他線程上的代碼中,除非其中一個其他線程遇到斷點。

請參閲

調試多線程應用如何:在調試時切換到另一個線程如何: 使用並行堆棧窗口如何:使用“並行監視”窗口