スレッドをデバッグするためのヒント
この記事では、ネイティブ コードおよびマネージド コードのスレッド名の設定に関する情報など、スレッドのデバッグに役立つ情報を提供します。
C/C++ のヒント
ここでは、ネイティブ コード内のスレッドをデバッグするときに役立つヒントを紹介します。
[ウォッチ] ウィンドウまたは [クイック ウォッチ] ダイアログ ボックスで「
@TIB
」と入力すると、[スレッド情報ブロック] の内容を表示できます。[ウォッチ] ウィンドウまたは [クイック ウォッチ] ダイアログ ボックスで「
@Err
」と入力すると、現在のスレッドの最終エラー コードを表示できます。マルチスレッド アプリケーションのデバッグには、C ランタイム ライブラリ (CRT) 関数を使用できます。 詳細については、「_malloc_dbg」を参照してください。
C/C++ のスレッド名を設定する
スレッド名の設定は、Visual Studio のどのエディションでも実行できます。 スレッドの名前付けは、実行中のプロセスをデバッグするときに、[スレッド] ウィンドウで対象のスレッドを識別するために役立ちます。 スレッドにわかりやすい名前を付けると、クラッシュ ダンプ検査を介して事後デバッグを実行するときや、さまざまなツールを使用してパフォーマンス キャプチャを分析するときにも役立ちます。
スレッド名を設定する方法
スレッド名を設定するには、2 つの方法があります。 1 つ目は、SetThreadDescription 関数を使用する方法です。 2 つ目は、Visual Studio デバッガーがプロセスにアタッチされているときに特定の例外をスローする方法です。 それぞれのアプローチに利点と注意点があります。 SetThreadDescription
の使用は、Windows 10 バージョン 1607 または Windows Server 2016 以降でサポートされています。
特記事項として、これらのメカニズムは互いに独立しているため、必要に応じて、両方のアプローチを同時に使用できます。
SetThreadDescription
を使用してスレッド名を設定する
利点:
- スレッド名は、SetThreadDescription が呼び出されたときにデバッガーがプロセスにアタッチされていたかどうかに関係なく、Visual Studio でデバッグするときに表示されます。
- Visual Studio でクラッシュ ダンプを読み込んで事後デバッグを実行すると、スレッド名が表示されます。
- スレッド名は、WinDbg デバッガーや Windows パフォーマンス アナライザー パフォーマンス アナライザーなどの他のツールを使用しているときにも表示されます。
注意事項:
- スレッド名は、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;
}
例外をスローしてスレッド名を設定する
プログラムでスレッド名を設定するもう 1 つの方法は、特別に構成された例外をスローして、目的のスレッド名を Visual Studio デバッガーに通知することです。
利点:
- Visual Studio のすべてのバージョンで動作します。
注意事項:
- デバッガーがアタッチされ、例外ベースの方法が使用されている場合にのみ動作します。
- この方法を使用して設定されたスレッド名は、ダンプまたはパフォーマンス分析ツールでは使用できません。
例:
以下に示す SetThreadName
関数は、この例外ベースのアプローチを示しています。 スレッド名は自動的にスレッドにコピーされるので、SetThreadName
の呼び出しが完了した後、threadName
パラメーターのメモリを解放できることに注意します。
//
// 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();
}