Udostępnij za pośrednictwem


Wskazówki na potrzeby debugowania wątków

Ten artykuł zawiera przydatne informacje dotyczące debugowania wątków, w tym informacje dotyczące ustawiania nazw wątków dla kodu natywnego i zarządzanego.

Porady dotyczące języka C/C++

Poniżej przedstawiono kilka wskazówek, których można użyć podczas debugowania wątków w kodzie natywnym:

  • Zawartość bloku informacji o wątku można wyświetlić, wpisując @TIB w oknie Zegarek lub w oknie dialogowym QuickWatch .

  • Ostatni kod błędu dla bieżącego wątku można wyświetlić, wprowadzając w @Err oknie kontrolnym lub w oknie dialogowym QuickWatch .

  • Funkcje bibliotek czasu wykonywania języka C (CRT) mogą być przydatne do debugowania aplikacji wielowątku. Aby uzyskać więcej informacji, zobacz _malloc_dbg.

Ustawianie nazwy wątku w języku C/C++

Nazewnictwo wątków jest możliwe w dowolnej wersji programu Visual Studio. Nazewnictwo wątków jest przydatne do identyfikowania interesujących wątków okna Wątki podczas debugowania uruchomionego procesu. Rozpoznawalne nazwane wątki mogą być również przydatne podczas przeprowadzania debugowania pośmiertnego za pośrednictwem inspekcji zrzutu awaryjnego i analizowania przechwytywania wydajności przy użyciu różnych narzędzi.

Sposoby ustawiania nazwy wątku

Istnieją dwa sposoby ustawiania nazwy wątku. Pierwszy to funkcja SetThreadDescription . Drugim jest zgłoszenie określonego wyjątku, gdy debuger programu Visual Studio jest dołączony do procesu. Każde podejście ma zalety i zastrzeżenia. Korzystanie z programu SetThreadDescription jest obsługiwane w systemie Windows 10 w wersji 1607 lub Windows Server 2016.

Warto zauważyć, że oba podejścia mogą być używane razem, w razie potrzeby, ponieważ mechanizmy, za pomocą których działają, są niezależne od siebie.

Ustawianie nazwy wątku przy użyciu polecenia SetThreadDescription

Korzyści:

  • Nazwy wątków są widoczne podczas debugowania w programie Visual Studio, niezależnie od tego, czy debuger został dołączony do procesu w momencie wywołania polecenia SetThreadDescription.
  • Nazwy wątków są widoczne podczas debugowania pośmiertnego przez załadowanie zrzutu awaryjnego w programie Visual Studio.
  • Nazwy wątków są również widoczne podczas korzystania z innych narzędzi, takich jak debuger WinDbg i analizator wydajności systemu Windows Analizator wydajności.

Zastrzeżenia:

  • Nazwy wątków są widoczne tylko w programie Visual Studio 2017 w wersji 15.6 lub nowszej.
  • Podczas debugowania po zakończeniu debugowania pliku zrzutu awaryjnego nazwy wątków są widoczne tylko wtedy, gdy awaria została utworzona w systemie Windows 10 w wersji 1607, Windows Server 2016 lub nowszej wersji systemu Windows.

Przykład:

#include <windows.h>
#include <processthreadsapi.h>

int main()
{
    HRESULT r;
    r = SetThreadDescription(
        GetCurrentThread(),
        L"ThisIsMyThreadName!"
    );

    return 0;
}

Ustawianie nazwy wątku przez zgłoszenie wyjątku

Innym sposobem ustawienia nazwy wątku w programie jest przekazanie żądanej nazwy wątku do debugera programu Visual Studio przez zgłoszenie specjalnie skonfigurowanego wyjątku.

Korzyści:

  • Działa we wszystkich wersjach programu Visual Studio.

Zastrzeżenia:

  • Działa tylko wtedy, gdy debuger jest dołączony w momencie użycia metody opartej na wyjątkach.
  • Nazwy wątków ustawione przy użyciu tej metody nie będą dostępne w narzędziach do analizy wydajności ani zrzutów.

Przykład:

Poniższa SetThreadName funkcja demonstruje to podejście oparte na wyjątkach. Należy pamiętać, że nazwa wątku zostanie automatycznie skopiowana do wątku, aby pamięć dla threadName parametru mogła zostać zwolniona po zakończeniu SetThreadName wywołania.

//
// Usage: SetThreadName ((DWORD)-1, "MainThread");
//
#include <windows.h>
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
    DWORD dwType; // Must be 0x1000.
    LPCSTR szName; // Pointer to name (in user addr space).
    DWORD dwThreadID; // Thread ID (-1=caller thread).
    DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void SetThreadName(DWORD dwThreadID, const char* threadName) {
    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.szName = threadName;
    info.dwThreadID = dwThreadID;
    info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
    __try{
        RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
    }
    __except (EXCEPTION_EXECUTE_HANDLER){
    }
#pragma warning(pop)
}

Ustawianie nazw wątków w kodzie zarządzanym

Nazewnictwo wątków jest możliwe w dowolnej wersji programu Visual Studio. Nazewnictwo wątków jest przydatne do śledzenia wątków w oknie Wątki .

Aby ustawić nazwę wątku w kodzie zarządzanym, użyj Name właściwości .

Przykład

public class Needle
{
    // This method will be called when the thread is started.
    public void Baz()
    {
        Console.WriteLine("Needle Baz is running on another thread");
    }
}

public void Main()
{
    Console.WriteLine("Thread Simple Sample");
    Needle oNeedle = new Needle();
    // Create a Thread object.
    System.Threading.Thread oThread = new System.Threading.Thread(oNeedle.Baz);
    // Set the Thread name to "MyThread".
    oThread.Name = "MyThread";
    // Starting the thread invokes the ThreadStart delegate
    oThread.Start();
}