スレッドからスレッドIDを取得する


319

たとえば、C#では、スレッドをデバッグするときに、各スレッドのIDを確認できます。

プログラムで同じスレッドを取得する方法が見つかりませんでした。(のプロパティでThread.currentThread)現在のスレッドのIDを取得することもできませんでした。

では、Visual StudioはどのようにスレッドのIDを取得するの2345でしょうか。たとえば、idを使用してスレッドのハンドルを取得する方法はありますか。

回答:


437

GetThreadId指定されたネイティブスレッドのIDを返します。マネージスレッドで機能させる方法はいくつかあります。きっと、スレッドハンドルを見つけてその関数に渡すだけです。

GetCurrentThreadId 現在のスレッドのIDを返します。

GetCurrentThreadId.NET 2.0で非推奨になりました。推奨される方法はThread.CurrentThread.ManagedThreadIdプロパティです。


87
これを見つけて入力し、それが非推奨であると言われたため、これを行う現在の方法はThread.CurrentThread.ManagedThreadId
James

3
ManagedThreadIdは、ManagedThreadIdプロパティIDがアプリで再利用されるときにスレッドを識別するための堅牢なアプローチではありません。そのため、一部のシナリオではスレッドの信頼できる識別子ではなく、「同じキーのアイテムが既に追加されています」という例外が発生します。at line ...作成時にスレッドに一意の名前を付けます。
Forer

15
この投稿には非常に悪いアドバイスがいくつかあります。「ManagedThreadId」を使用してスレッドを識別することを推奨している人もいます。私は投稿を編集して推奨事項を削除しました-非常に少数が指摘したのは、さまざまなタイプのスレッドIDがあることです。マネージスレッドIDは、アンマネージスレッドIDと同じものではありません。そのコードをコピーして貼り付けると、非常に微妙な同期のバグが発生する可能性があります。スレッドクラスに関するMSDNのドキュメントは、これについて非常に明確です。クラスレベルでコメントを表示します。
ShadowChaser 2013

3
ただし、IDでは同期せず、ミューテックスなどの同期プリミティブを使用します。これはデバッグ専用です。
ブリンディ2013

11
このコメントを投稿してSystem.Threading.Thread.CurrentThread.ManagedThreadId、少なくともで使用すると機能しないことに注意してくださいSetWindowsHookEx。代わりに、ネイティブのwin32関数からスレッドIDを取得する必要がありますGetCurrentThreadId()
キングキング

82

たとえば、C#では、スレッドをデバッグするときに、各スレッドのIDを確認できます。

これは、管理対象スレッドのIDになります。 ManagedThreadIdのメンバーなThreadので、任意のThreadオブジェクトからIDを取得できます。これにより、現在のManagedThreadIDが取得されます。

Thread.CurrentThread.ManagedThreadId

OSスレッドID (ManagedThreadIDではない)でOSスレッドを取得するには、linqを少し試してみます。

int unmanagedId = 2345;
ProcessThread myThread = (from ProcessThread entry in Process.GetCurrentProcess().Threads
   where entry.Id == unmanagedId 
   select entry).First();

マネージスレッドを列挙する方法はなく、ProcessThreadとThreadの関係もないようです。そのため、マネージスレッドをIDで取得するのは難しいものです。

マネージスレッドとアンマネージスレッドの詳細については、このMSDNアークティックスを参照してください。


4
なぜ誰もこの簡単な答えを考え出さなかったのですか?
Stefan Steinegger、2010年

2
これは動作しません。GetCurrentProcess()。Threadsは、Threadsに変換できないProcessThreadCollectionを返します。簡単な解決策はありません。
mafu

2
@ mafutrct、更新された回答。そのプロパティは実際には.ProcessThreadsと呼ばれるべきです!ありがとう。
badbod99

2
2つのスレッドIDが異なることを明確にするために、この投稿を書き直すことをお勧めします。誰かが最後の文を読み損なった場合、ManagedThreadIdをプラグインして、それをProcessThread.Idにマッピングしようとするだけで、大混乱を引き起こします。
ShadowChaser 2013

1
違いを強調する役立つMSDNアクティクルへのリンクを追加しました。ただし、問題はデバッグ用のスレッドID(この場合はManagedThreadID)の取得に関するものでした。OSとマネージスレッドの違いの詳細で答えを散らかすことは役に立たないと思います。
badbod99 2013

46

廃止予定AppDomain.GetCurrentThreadIdを使用して、現在実行中のスレッドのIDを取得できます。このメソッドは、Win32 APIメソッドへのPInvokeを使用しGetCurrentThreadID、WindowsスレッドIDを返します。

.NETスレッドオブジェクトが単一のWindowsスレッドに対応せず、特定の.NETスレッドに対してWindowsから返される可能性のある安定したIDがないため、このメソッドは非推奨としてマークされています。

これが事実である理由の詳細については、コンフィギュレーターの回答を参照してください。


注意.Net Core 2.2では、AppDomain.GetCurrentThreadId(MethodInfoを介して廃止として呼び出しました)がマネージスレッドIDを返すことに注意してください(一致するProcess.GetCurrentProcess()。Threadsコレクションには
不要

32

OS IDを取得するには:

AppDomain.GetCurrentThreadId()

1
GetHashCodeは必ずしも一意である必要はありません。スレッドの識別には使用しないでください。
Dror Helper、

2
OSスレッドIDが必要な場合はAppDomain.GetCurrentThreadId()を使用できますが、理論上、複数の.NETスレッドが同じOSスレッドを共有する可能性があります。Thread.GetHashCode()は、プロセス全体で一意の値を返すことが保証されています。
Mark Byers、

3
このメソッドは非推奨としてマークされており、それには十分な理由があります。全体像については、私の回答とコンフィギュレーターを参照してください。
ポールターナー、

3
これがOSスレッドIDを取得する唯一の方法です。そして、これは正しい答えとしてマークされるべきです。それはもうこれに依存するつもりはありませんが。
LolaRun 2009年

1
AppDomain.GetCurrentThreadId()は廃止AppDomain.GetCurrentThreadId されましたfibers (aka lightweight threads)。マネージスレッドがで実行されているときに安定したIDを提供しないため、廃止されました。マネージスレッドの安定した識別子を取得するには、のManagedThreadIdプロパティを使用しますThread。使用法:Thread.CurrentThread.ManagedThreadId
リホジョセフ2016

22

MSDNによると:

非管理対象ホストは管理対象スレッドと非管理対象スレッドの関係を制御できるため、オペレーティングシステムのThreadIdと管理対象スレッドとの間に固定の関係はありません。具体的には、高度なホストはCLR Hosting APIを使用して、同じオペレーティングシステムスレッドに対して多くのマネージスレッドをスケジュールしたり、マネージスレッドを異なるオペレーティングシステムスレッド間で移動したりできます。

したがって、基本的に、Threadオブジェクトは必ずしもOSスレッドに対応しているわけではありません。そのため、ネイティブIDが公開されていません。


VS2010の[デバッグ/スレッド]ウィンドウに「マネージスレッドID」が表示されます。どうすれば入手できますか?
Pavel Radzivilovsky、2010

1
ManagedThreadIDプロパティmsdn.microsoft.com/en-us/library/…を使用します。ただし、これはOSスレッドIDとは異なります。
コンフィギュレー

15

ハッキングしようとしている人のために:

    public static int GetNativeThreadId(Thread thread)
    {
        var f = typeof(Thread).GetField("DONT_USE_InternalThread",
            BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

        var pInternalThread = (IntPtr)f.GetValue(thread);
        var nativeId = Marshal.ReadInt32(pInternalThread, (IntPtr.Size == 8) ? 548 : 348); // found by analyzing the memory
        return nativeId;
    }

11

現在のスレッドIDを見つけるには、「Thread.CurrentThread.ManagedThreadId」を使用します。ただし、この場合、現在のwin32スレッドIDが必要になる可能性があります。この関数で取得するには、pInvokeを使用します。

[DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
public static extern Int32 GetCurrentWin32ThreadId();

最初に、マネージスレッドIDとwin32スレッドID接続を保存する必要があります-win32 IDをマネージスレッドにマップする辞書を使用します。

次に、IDでスレッドを見つけるには、Process.GetCurrentProcess()。Threadsを使用してプロセスのスレッドを反復処理し、そのIDのスレッドを見つけます。

foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
{
     var managedThread = win32ToManagedThread[thread.id];
     if((managedThread.ManagedThreadId == threadId)
     {
         return managedThread;
     }
}

OPがスレッドのOS IDを要求していると思いますが、これはマネージスレッドIDとは異なります。
ブライアンラスムッセン

Process.Threadsがのコレクションを返します。このコードは動作しませんProcessThread、これはと同じではありません、オブジェクトを(またそれを継承しています)Thread(thread as Thread)nullの参照を返します。
FredrikMörk09年

コードコードにいくつかのバグがあることに気づきました-修正して今すぐ試してください
Dror Helper

1
結局、win32 idをマネージスレッドにマップする辞書を使用することになりました。
Contango 2012

11

Windows 10でのオフセットは0x022C(x64-bit-Application)と0x0160(x32-bit-Application)です。

public static int GetNativeThreadId(Thread thread)
{
    var f = typeof(Thread).GetField("DONT_USE_InternalThread",
        BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

    var pInternalThread = (IntPtr)f.GetValue(thread);
    var nativeId = Marshal.ReadInt32(pInternalThread, (IntPtr.Size == 8) ? 0x022C : 0x0160); // found by analyzing the memory
    return nativeId;
}

1
Windows 7 x64 SP1でも動作します。でもお勧めしません。一時的なテストでのみ使用します。
グアンボシェン

5

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId

5

マネージコードからThread、各マネージスレッドのタイプのインスタンスにアクセスできます。ThreadOSスレッドの概念をカプセル化し、現在のCLR以降、マネージスレッドおよびOSスレッドと1対1で対応しています。ただし、これは実装の詳細であり、将来変更される可能性があります。

Visual Studioによって表示されるIDは、実際にはOSスレッドIDです。これはない、いくつかの回答により示唆されるように管理するスレッドIDと同じ。

Threadタイプと呼ばれる民間のIntPtrメンバーフィールド含まれていDONT_USE_InternalThreadた点を基本的なOS構造にし、。ただし、これは実際の実装の詳細であるため、このIMOを追求することはお勧めできません。そして、一種の名前は、これに依存すべきではないことを示しています。


GetThreadIdを使用するには、DONT_USEフィールドから取得するハンドルが必要です。
コンフィギュレー

私は知っていますが、先に述べたように、マネージスレッドがOSスレッドに直接マップされるという事実を実際に当てにすることはできないので、私はそれに頼りません。
Brian Rasmussen

説明と問題のまとめに感謝します。しかし、複数のマネージスレッドが単一のOSスレッドに対応できる場合(コンフィギュレーターが述べたように、そして彼に感謝します)、これはVSがマネージスレッドではなくOSスレッドを表示していることを意味します。
LolaRun 2009年

@OhrmaZd:はい、VS2005 / 2008では、[スレッド]ウィンドウに管理対象スレッドのOS IDが表示されます。VS2010B2は、実際にはスレッドごとにOSと管理IDの両方を表示します。
ブライアンラスムッセン

@Brian Rasmussen:これがマネージスレッドのIDです。あなたの知識を共有してくれてありがとう。
LolaRun 2009年

4

マネージスレッドIDを返すThread.GetHashCodeを使用できます。GetHashCodeの目的を考えると、これは理にかなっています。オブジェクト(スレッド)の一意の識別子(たとえば、辞書のキー)である必要があります。

Threadクラス参照ソースは、ここで参考になります。(確かに、特定の.NET実装このソースコードに基づいていない可能性がありますが、デバッグの目的で私はチャンスを利用します。)

GetHashCodeは、「オブジェクトの等価性の迅速なチェックが必要なアルゴリズムにこのハッシュコードを提供する」ため、スレッドの等価性のチェックに適しています。たとえば、特定のメソッドが呼び出し元のスレッドで実行されていることをアサートする場合などです。


4
すごい、私はこの5年前の質問を1時間開いていて、戻ってきて "この質問に対する1つの新しい答え"を見た:D
Ray

この答えは別のコメントでほのめかされましたが、私はいくつかのさらなる調査の後に私が最終的に使用したものでした。おそらく、OPが望んでいないものです。おそらく、OPはもう関係ありません。他の誰かに役立つかもしれません。(そして、少なくとも参照ソースに基づいて、これはスレッドIDを取得する最も効率的な方法かもしれません。)
yoyo

さて、今は別のフィールドにいますが、当時、スレッドには2つのID、ネイティブスレッドのID、およびマネージスレッドのIDがあり、1つは別のIDに属しています...主に、 IDはスレッドを識別するためのもので、GetHashCodesには他のユーティリティがあり、衝突する可能性があります。GetHashCodeを使用する必要がある場合、フレームワーク開発者はIDを実装しなかったでしょう
LolaRun 2014年

3
@yoyo衝突によって辞書の使用が中断されることはありません。それらは衝突の可能性が低く、まったく衝突しないように設計されています。128ビット値を64ビット値にハッシュすると、すべてのハッシュ値で約2 ^ 64の衝突が発生します。この辞書は、まれに衝突が発生したときにフォールバックアルゴリズムを使用するように設計されています。
Bradgonesurfing 2017年

2
@bradgonesurfingあなたは絶対に正しいです、そして私の前のコメントは間違っています。ハッシュの衝突により、辞書のパフォーマンスは低下しますが、機能はそのままです。誤解を招くコメントをお詫びします。指摘していただきありがとうございます。
ヨーヨー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.