2009-11-05 7 views
227

В C# при отладке потоков, например, вы можете увидеть идентификатор каждого потока.Получение идентификатора потока из потока

Я не мог найти способ получить тот же поток, программно. Я даже не мог получить идентификатор текущего потока (в свойствах Thread.currentThread).

Итак, интересно, как Visual Studio получает идентификаторы потоков, и есть ли способ получить дескриптор потока с идентификатором 2345, например?

ответ

347

GetThreadId возвращает идентификатор данного нативного потока. Есть способы заставить его работать с управляемыми потоками, я уверен, все, что вам нужно найти, это дескриптор потока и передать его этой функции.

GetCurrentThreadId возвращает идентификатор текущей резьбы.

GetCurrentThreadId устарел от .NET 2.0: рекомендуемым способом является свойство Thread.CurrentThread.ManagedThreadId.

+0

Ну если есть управляемый ответ без dllimport, я должен принять его ответ. Но большое спасибо за усилия. И я мог бы использовать ваш ответ, так как он надежный. – LolaRun

+0

Это ближе к реальной вещи (читайте на родной стороне), поскольку управляемые потоки могут быть переведены на волокна, работающие на одном родном потоке, и поскольку вы упомянули об отладчике vs, это, вероятно, то, что вы хотите. – Blindy

+71

Поскольку я нашел это, набрал его, а затем было сказано, что он устарел, текущий способ сделать это - Thread.CurrentThread.ManagedThreadId – James

24

Чтобы использовать OS ID:

AppDomain.GetCurrentThreadId() 
+1

GetHashCode не обязательно уникален! и не должен использовать его для идентификации потока. –

+2

Вы можете использовать AppDomain.GetCurrentThreadId(), если хотите идентификатор потока ОС, но несколько потоков .NET могут теоретически совместно использовать один и тот же поток ОС. Thread.GetHashCode() гарантированно вернет значение, которое является уникальным для всего процесса, чего вы, вероятно, хотите. –

+0

Возможно 'AppDomain.GetCurrentThreadId();' был бы лучшим ответом на этот вопрос. Должен ли я дважды ответить на вопрос? Удалить это? Или кто-то должен это предложить, тогда я их проголосую. :) –

4

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId 
+1

Это не идентификатор потока. –

7

Чтобы найти текущий поток Id use - `Thread.CurrentThread.ManagedThreadId '. Но в этом случае вам, возможно, потребуется текущий идентификатор win32 нити - используйте PInvoke, чтобы получить его с помощью этой функции:

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

Сначала вам нужно, чтобы сохранить управляемый идентификатор потока и соединения нити ID win32 - использовать словарь который сопоставляет идентификатор win32 управляемому потоку.

Тогда, чтобы найти поток, это идентификатор итерация над нитью текущего процесса с использованием Process.GetCurrentProcess() Нитки и найти нить с этим идентификатором:.

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

Я считаю, что ОП запрашивает идентификатор ОС для потока, который не совпадает с идентификатором управляемого потока. –

+0

Этот код не работает: Process.Threads возвращает коллекцию объектов ProcessThread, это не то же самое, что (и не наследует) 'Thread':' (thread as Thread) 'будет возвращать нулевую ссылку. –

+0

Я заметил, что в коде кода было несколько ошибок - исправлено это сейчас. –

5

Из управляемого кода вы имеете доступ к экземплярам Thread Тип для каждой управляемой нити. Thread инкапсулирует концепцию потока ОС, и с текущей CLR существует взаимно однозначное соответствие управляемым потокам и потокам ОС. Однако это детализация реализации, которая может измениться в будущем.

Идентификатор, отображаемый Visual Studio, фактически является идентификатором потока ОС. Это не то же, что и идентификатор управляемого потока, как это предлагается несколькими ответами.

Тип Thread включает частное поле члена IntPtr, которое называется DONT_USE_InternalThread, что указывает на основную структуру ОС. Однако, поскольку это действительно деталь реализации, нецелесообразно преследовать эту ИМО. И имя типа указывает, что вы не должны полагаться на это.

+0

Чтобы использовать GetThreadId, вам понадобится дескриптор, который вы получаете из поля DONT_USE. – configurator

+0

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

+0

Большое спасибо за разъяснение и суммируем проблему. Но теперь, если несколько управляемых потоков могут соответствовать одному потоку ОС (как указано конфигуратором - и он был благодарен), это означает, что VS показывает потоки ОС, а не управляемые потоки. – LolaRun

20

В соответствии с MSDN:

Операционной система-ThreadId не имеет отношения фиксированных к управляемой нити, потому что неуправляемый хост может контролировать отношения между управляемыми и неуправляемыми потоками. В частности, сложный хост может использовать CLR Hosting API для планирования многих управляемых тема от одной и тех же системы потоков операционных или переместить управляемой нити между различной операционной системой нитями.

Таким образом, объект Thread не обязательно соответствует потоку ОС, поэтому он не имеет открытого идентификатора.

+0

Окно Debug/Threads в VS2010 показывает «Управляемый идентификатор потока». Как я могу получить этот? –

+1

Используйте свойство ManagedThreadID http://msdn.microsoft.com/en-us/library/system.threading.thread.managedthreadid.aspx. Это не то же самое, что и идентификатор потока ОС. – configurator

37

Вы можете использовать устаревший AppDomain.GetCurrentThreadId, чтобы получить идентификатор текущей выполняемой темы. Этот метод использует PInvoke для метода Win32 API GetCurrentThreadID и возвращает идентификатор потока Windows.

Этот метод отмечен как устаревший, поскольку объект .NET Thread не соответствует ни одному потоку Windows, и поэтому нет стабильного идентификатора, который может быть возвращен Windows для данного потока .NET.

См. Ответ конфигуратора по нескольким причинам, почему это так.

58

В C# при отладке потоков, например, вы можете увидеть идентификатор каждого потока.

Это будут идентификаторы управляемых потоков. ManagedThreadId является членом Thread, поэтому вы можете получить идентификатор от любого объекта Thread. Это позволит получить текущее ManagedThreadID:

Thread.CurrentThread.ManagedThreadId 

Чтобы получить нить ОС на это OS нить ID (не ManagedThreadID), вы можете попробовать немного LINQ.

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

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

Для получения дополнительной информации о Managed vs Unmanaged threading см. this MSDN arcticle.

+4

Почему никто другой не придумал этот простой ответ? –

+2

Это не работает. GetCurrentProcess(). Threads возвращает ProcessThreadCollection, который не конвертируется в Threads. Я не вижу легкого решения. – mafu

+2

@ mafutrct, обновленный ответ. Это свойство действительно нужно называть .ProcessThreads! Благодарю. – badbod99

11

Для тех, кто собирается взломать:

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; 
    } 
+0

не будет работать сейчас, он получил -1 – raidsan

3

Вы можете использовать Thread.GetHashCode, который возвращает управляемый идентификатор потока. Если вы думаете о цели GetHashCode, это имеет смысл - для объекта (потока) он должен быть уникальным идентификатором (например, ключом в словаре).

reference source for the Thread class поучителен здесь. (Конечно, конкретная реализация .NET может не основываться на этом исходном коде, но для целей отладки я рискну.)

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

+1

Удивительный, у меня только этот 5-летний вопрос был открыт в течение часа, вернулся и увидел «1 новый ответ на этот вопрос»: D –

+0

Этот ответ был намечен в другом комментарии , но это то, что я закончил использовать после некоторых дальнейших исследований. Возможно, не то, что хотел OP. Вероятно, ФП больше не волнует. Может быть полезно кому-то другому. (И, по крайней мере, на основе источника ссылки, это может быть наиболее эффективным способом получения идентификатора потока.) – yoyo

+0

ну, я сейчас в другом поле, но тогда у нас было два идентификатора для потока, id собственного потока и идентификатора управляемого потока, а один принадлежит другому ... В принципе, идентификаторы предназначены для идентификации потоков, GetHashCodes имеют другую полезность и могут сталкиваться. Разработчики Framework не реализовали бы идентификатор, если бы нам пришлось использовать GetHashCode – LolaRun

1

Смещение под Windows 10 является 0x022C (64-разрядные приложения) и 0x0160 (x32-разрядные приложения):

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; 
} 
Смежные вопросы