Поделиться через


Советы для отладки потоков

В этой статье содержатся полезные сведения об отладке потоков, включая сведения о настройке имен потоков для машинного и управляемого кода.

Советы по C/C++

Ниже приведены некоторые советы по отладке потоков в машинном коде.

  • Можно просмотреть содержимое блока информации потока, введя @TIB в окно Контрольные значения или диалоговое окно Быстрая проверка.

  • Можно просмотреть код последней ошибки текущего потока, введя @Err в окно Контрольные значения или диалоговое окно Быстрая проверка.

  • Для отладки многопоточного приложения можно использовать функции библиотеки времени выполнения C (CRT). Дополнительные сведения см. в разделе _malloc_dbg.

Задание имени потока в C/C++

Именование потоков можно выполнить в любом выпуске Visual Studio. Именование потоков позволяет находить необходимые потоки в окне Потоки при отладке выполняемого процесса. Наличие распознаваемых именованных потоков также может оказаться полезным при выполнении последующей отладки с помощью проверки аварийного дампа и при анализе записей производительности с помощью различных средств.

Способы задания имени для потока

Имя для потока можно задать одним из двух способов. Во-первых, с помощью функции SetThreadDescription. Во-вторых, создав определенное исключение, когда отладчик Visual Studio подключается к процессу. Каждый подход имеет свои преимущества и недостатки. Использование SetThreadDescription поддерживается начиная с Windows 10 версии 1607 или Windows Server 2016.

Следует отметить, что оба подхода можно использовать вместе, если это необходимо, так как механизмы, с помощью которых они работают, не зависят друг от друга.

Задание имени для потока с помощью функции SetThreadDescription

Преимущества:

  • Имена потоков отображаются при отладке в Visual Studio независимо от того, был ли отладчик присоединен к процессу во время вызова функции SetThreadDescription.
  • Имена потоков отображаются при выполнении отладки после аварийного завершения путем загрузки аварийного дампа в Visual Studio.
  • Имена потоков отображаются и при работе с другими средствами, такими как отладчик WinDbg и анализатор производительности Windows Performance Analyzer.

Предупреждения:

  • Имена потоков отображаются только в Visual Studio 2017 версии 15.6 и более поздних версий.
  • При отладке файла аварийного дампа после аварийного завершения имена потоков отображаются только в том случае, если сбой произошел в Windows 10 версии 1607, Windows Server 2016 или более поздних версиях Windows.

Пример:

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

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

    return 0;
}

Задание имени для потока путем создания исключения

Другой способ задать имя потока в программе — передать требуемое имя потока отладчику Visual Studio путем создания специально настроенного исключения.

Преимущества:

  • Работает во всех версиях Visual Studio.

Предупреждения:

  • Работает только в том случае, если отладчик был подключен в момент применения метода исключений.
  • Имена потоков, заданные с помощью этого метода, не будут доступны в дампах или средствах анализа производительности.

Пример:

Представленная ниже функция SetThreadName демонстрирует метод исключений. Обратите внимание на то, что имя потока автоматически копируется в поток, чтобы можно было освободить память для параметра threadName после того, как вызов функции 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)
}

Установка имени потока в управляемом коде

Именование потоков можно выполнить в любом выпуске Visual Studio. Именование потоков позволяет отслеживать их в окне Потоки.

Чтобы задать имя потока в управляемом коде, используйте свойство Name.

Пример

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