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++

Veja algumas dicas que você pode usar durante a depuração de threads em código nativo:

  • Você pode exibir o conteúdo do bloco de informações sobre o thread digitando @TIB na janela Inspeção ou na caixa de diálogo QuickWatch.

  • Para exibir o último código de erro do thread atual, digite @Err na janela Inspeção ou na caixa de diálogo QuickWatch.

  • As funções das bibliotecas em tempo de execução do C (CRT) 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 nomeação 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-morte por meio da inspeção de despejo de memória e ao analisar capturas de desempenho 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 possui benefícios e desvantagens. O uso de SetThreadDescription é possível a partir do Windows 10, versão 1607 ou Windows Server 2016.

Vale a pena observar que ambas as abordagens podem ser usadas juntas, se desejar, pois os mecanismos por meio dos quais elas 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 ficam visíveis ao executar a depuração pós-morte carregando um despejo de memória 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 Windows Performance Analyzer.

Restrições:

  • Os nomes de thread só são visíveis no Visual Studio 2017 versão 15.6 e versões posteriores.
  • Ao depurar um arquivo de despejo de memória pós-morte, os nomes de thread só ficarão visíveis se a falha tiver sido criada no Windows 10 versão 1607, Windows Server 2016 ou versões posteriores do Windows.

Exemplo:

#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 do thread desejado para o depurador do Visual Studio lançando uma exceção especialmente configurada.

Benefícios:

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

Restrições:

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

Exemplo:

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

//
// 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 nomeação de thread é possível em qualquer edição do Visual Studio. A nomeação de thread é útil para manter o controle de threads na janela Threads.

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

Exemplo

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