Suggerimenti per il debug dei thread

Questo articolo fornisce informazioni utili per il debug dei thread, incluse informazioni sull'impostazione dei nomi di thread per il codice nativo e gestito.

Suggerimenti per C/C++

Di seguito sono riportati alcuni suggerimenti che è possibile utilizzare durante il debug dei thread in codice nativo:

  • È possibile visualizzare il contenuto del blocco di informazioni del thread immettendo @TIB nella finestra Espressioni di controllo o nella finestra di dialogo Controllo immediato.

  • È possibile visualizzare l'ultimo codice di errore per il thread corrente immettendo @Err nella finestra Espressioni di controllo o nella finestra di dialogo Controllo immediato.

  • Per il debug di applicazioni multithreading è possibile utilizzare le funzioni delle librerie di runtime del linguaggio C (CRT). Per altre informazioni, vedere _malloc_dbg.

Impostare un nome di thread in C/C++

La denominazione dei thread è possibile in tutte le edizioni di Visual Studio. La denominazione dei thread è utile per identificare i thread di interesse nella finestra Thread durante il debug di un processo in esecuzione. La presenza di thread denominati riconoscibili può essere utile anche quando si esegue il debug post-mortem tramite l'ispezione dei dump di arresto anomalo del sistema e quando si analizzano le prestazioni tramite vari strumenti.

Modi per impostare un nome di thread

Esistono due modi per impostare un nome di thread. Il primo è tramite la funzione SetThreadDescription . Il secondo consiste nel generare una particolare eccezione mentre il debugger di Visual Studio è collegato al processo. Ogni approccio presenta vantaggi e avvertenze. L'uso di SetThreadDescription è supportato a partire da Windows 10 versione 1607 o Windows Server 2016.

Vale la pena notare che entrambi gli approcci possono essere usati insieme, se necessario, poiché i meccanismi in base ai quali funzionano sono indipendenti l'uno dall'altro.

Impostare un nome di thread usando SetThreadDescription

Vantaggi:

  • I nomi dei thread sono visibili durante il debug in Visual Studio, indipendentemente dal fatto che il debugger sia stato collegato al processo al momento in cui viene richiamato SetThreadDescription.
  • I nomi dei thread sono visibili quando si esegue il debug post-mortem caricando un dump di arresto anomalo in Visual Studio.
  • I nomi dei thread sono visibili anche quando si usano altri strumenti, ad esempio il debugger WinDbg e l'analizzatore delle prestazioni di Windows analizzatore prestazioni.

Avvertenze:

  • I nomi dei thread sono visibili solo in Visual Studio 2017 versione 15.6 e versioni successive.
  • Quando si esegue il debug di un file dump di arresto anomalo del sistema, i nomi dei thread sono visibili solo se l'arresto anomalo è stato creato in Windows 10 versione 1607, Windows Server 2016 o versioni successive di Windows.

Esempio:

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

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

    return 0;
}

Impostare un nome di thread generando un'eccezione

Un altro modo per impostare un nome di thread nel programma consiste nel comunicare il nome del thread desiderato al debugger di Visual Studio generando un'eccezione configurata appositamente.

Vantaggi:

  • Funziona in tutte le versioni di Visual Studio.

Avvertenze:

  • Funziona solo se il debugger è collegato al momento dell'utilizzo del metodo basato su eccezioni.
  • I nomi dei thread impostati tramite questo metodo non saranno disponibili nei dump o negli strumenti di analisi delle prestazioni.

Esempio:

La SetThreadName funzione illustrata di seguito illustra questo approccio basato su eccezioni. Si noti che il nome del thread verrà copiato automaticamente nel thread, in modo che la memoria per il threadName parametro possa essere rilasciata dopo il completamento della SetThreadName chiamata.

//
// 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)
}

Impostare il nome di un thread in codice gestito

La denominazione dei thread è possibile in tutte le edizioni di Visual Studio. Tale denominazione è utile per tenere traccia dei thread nella finestra Thread.

Per impostare il nome di un thread in codice gestito, usare la proprietà Name.

Esempio

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();
}