Compartilhar via


Dicas para depurar threads

Este artigo fornece informações úteis para depuração de threads, incluindo informações sobre como definir nomes de thread para código nativo e gerenciado.

Dicas de C/C++

Aqui estão algumas dicas que você pode usar ao depurar threads no código nativo:

  • Você pode exibir o conteúdo do Bloco de Informações do Thread digitando @TIB na janela Inspeção ou na caixa de diálogo Visualização Rápida.

  • Você pode exibir o último código de erro da thread atual inserindo @Err na janela Watch ou na caixa de diálogo QuickWatch.

  • As funções CRT (Bibliotecas de Run-Time C) podem ser úteis para depurar um aplicativo multithreaded. Para obter mais informações, consulte _malloc_dbg.

Definir um nome de thread em C/C++

A nomenclatura de thread é possível em qualquer edição do Visual Studio. A nomenclatura de thread é útil para identificar threads de interesse na janela Threads ao depurar um processo em execução. Ter threads com nomes reconhecíveis também pode ser útil ao executar a depuração pós-mortem por meio da inspeção de dump de memória e ao analisar captures de performance usando várias ferramentas.

Maneiras de definir um nome de thread

Há duas maneiras de definir um nome de thread. A primeira é por meio da função SetThreadDescription . A segunda é gerando uma exceção específica enquanto o depurador do Visual Studio está anexado ao processo. Cada abordagem tem benefícios e ressalvas. O uso de SetThreadDescription é suportado a partir do Windows 10 versão 1607 ou do Windows Server 2016.

Vale a pena observar que ambas as abordagens podem ser usadas em conjunto, se desejar, já que os mecanismos pelos quais funcionam são independentes uns dos outros.

Definir um nome de thread usando SetThreadDescription

Benefícios:

  • Os nomes de thread ficam visíveis durante a depuração no Visual Studio, independentemente de o depurador ter sido anexado ou não ao processo no momento em que SetThreadDescription é invocado.
  • Os nomes de thread são visíveis durante a depuração pós-morte ao carregar um arquivo de despejo no Visual Studio.
  • Os nomes de thread também são visíveis ao usar outras ferramentas, como o depurador WinDbg e o analisador de desempenho do Analisador de Desempenho do Windows .

Restrições:

  • Os nomes de thread só estão visíveis no Visual Studio 2017 versão 15.6 e versões posteriores.
  • Ao depurar um arquivo de despejo de memória após uma falha (post-mortem), os nomes das threads só serão visíveis se a falha tiver sido gerada no Windows 10 versão 1607, no Windows Server 2016 ou em versões posteriores do Windows.

Example:

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

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

    return 0;
}

Definir um nome de thread lançando uma exceção

Outra maneira de definir um nome de thread em seu programa é comunicar o nome de thread desejado para o depurador do Visual Studio gerando uma exceção especialmente configurada.

Benefícios:

  • Funciona em todas as versões do Visual Studio.

Restrições:

  • Só funcionará se o depurador estiver conectado no momento em que o método de exceção for usado.
  • Os nomes de thread definidos usando esse método não estarão disponíveis em arquivos de despejo ou em ferramentas de análise de desempenho.

Example:

A SetThreadName função mostrada abaixo demonstra essa abordagem baseada em exceção. Observe que o nome do thread será copiado automaticamente para o thread, de modo que a memória do threadName parâmetro possa ser liberada após a conclusão da SetThreadName chamada.

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

Definir um nome de thread no código gerenciado

A nomenclatura de thread é possível em qualquer edição do Visual Studio. A nomenclatura de thread é útil para manter o controle de threads na janela Threads .

Para definir um nome de thread no código gerenciado, use a Name propriedade.

Example

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