Ottenere l'ID thread da un thread


319

In C #, ad esempio durante il debug dei thread, puoi vedere l'ID di ogni thread.

Non sono riuscito a trovare un modo per ottenere lo stesso thread, a livello di codice. Non sono nemmeno riuscito a ottenere l'ID del thread corrente (nelle proprietà del Thread.currentThread).

Quindi, mi chiedo come fa Visual Studio a ottenere gli ID dei thread, e c'è un modo per ottenere l'handle del thread con id 2345, ad esempio?

Risposte:


437

GetThreadIdrestituisce l'ID di un determinato thread nativo. Ci sono modi per farlo funzionare con i thread gestiti, ne sono sicuro, tutto ciò che devi trovare è l'handle del thread e passarlo a quella funzione.

GetCurrentThreadId restituisce l'ID del thread corrente.

GetCurrentThreadIdè stato deprecato a partire da .NET 2.0: il modo consigliato è la Thread.CurrentThread.ManagedThreadIdproprietà.


87
Da quando l'ho trovato, digitato e poi mi è stato detto che era obsoleto, il modo attuale per farlo è Thread.CurrentThread.ManagedThreadId
James

3
ManagedThreadId non è un approccio affidabile per identificare i thread poiché l'ID della proprietà ManagedThreadId viene riutilizzato dalla tua app. Quindi non è un identificatore affidabile per i thread in alcuni scenari e si verificherà l'eccezione: "È già stato aggiunto un elemento con la stessa chiave". alla riga ... Assegna al thread un nome univoco quando lo crei.
Forer,

15
Ci sono dei pessimi consigli su questo post. Alcune persone consigliano di utilizzare "ManagedThreadId" per identificare un thread. Ho modificato il post per rimuovere la raccomandazione - ciò che pochissimi hanno sottolineato è che ci sono diversi tipi di ID thread. Gli ID thread gestiti non sono la stessa cosa degli ID thread non gestiti e se le persone dovessero copiare e incollare quel codice potrebbero verificarsi alcuni bug di sincronizzazione molto sottili. La documentazione su MSDN per la classe Thread è molto chiara al riguardo. Visualizza le osservazioni a livello di classe.
ShadowChaser,

3
Tuttavia, non ti sincronizzi sugli ID, usi le primitive di sincronizzazione come i mutex. Questo è solo a scopo di debug.
Blindy,

11
Vorrei pubblicare questo commento per notare che System.Threading.Thread.CurrentThread.ManagedThreadIdnon funzionerà almeno quando si utilizza in a SetWindowsHookEx. Invece dobbiamo ottenere l'id thread dalla funzione nativa win32 GetCurrentThreadId().
King King,

82

In C #, ad esempio durante il debug dei thread, puoi vedere l'ID di ogni thread.

Questi saranno gli ID dei thread gestiti. ManagedThreadIdè un membro di Threadcosì puoi ottenere l'ID da qualsiasi oggetto Thread . Questo ti porterà l'attuale ManagedThreadID :

Thread.CurrentThread.ManagedThreadId

Per ottenere un thread del sistema operativo tramite l'ID del thread del sistema operativo (non ManagedThreadID) , puoi provare un po 'di linq.

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

Sembra che non ci sia modo di enumerare i thread gestiti e nessuna relazione tra ProcessThread e Thread, quindi ottenere un thread gestito dal suo ID è difficile.

Per ulteriori dettagli sul threading gestito e non gestito, consultare questo articolo MSDN .


4
Perché nessun altro ha trovato questa semplice risposta?
Stefan Steinegger,

2
Questo non funziona. GetCurrentProcess (). Thread restituisce un ProcessThreadCollection, che non è convertibile in thread. Non vedo una soluzione semplice.
mafu,

2
@ mafutrct, risposta aggiornata. Quella proprietà dovrebbe davvero essere chiamata .ProcessThreads! Grazie.
badbod99,

2
Consiglia a questo post di essere riscritto per rendere più chiaro che i due ID thread sono diversi. Se qualcuno non riesce a leggere l'ultima frase, collegherà semplicemente ManagedThreadId e proverà a mapparlo su ProcessThread.Id, creando havok.
ShadowChaser

1
Ho aggiunto un collegamento a un utile articolo MSDN che evidenzia la differenza. Tuttavia, la domanda era correlata all'ottenimento dell'ID thread per il debug (che in questo caso è ManagedThreadID). Non penso che ingombrare la risposta con i dettagli della differenza tra sistema operativo e thread gestiti sia utile.
badbod99

46

È possibile utilizzare il deprecato AppDomain.GetCurrentThreadIdper ottenere l'ID del thread attualmente in esecuzione. Questo metodo utilizza un PInvoke per il metodo API Win32 GetCurrentThreadIDe restituirà l'ID thread di Windows.

Questo metodo è contrassegnato come obsoleto perché l'oggetto .NET Thread non corrisponde a un singolo thread di Windows e pertanto non esiste un ID stabile che può essere restituito da Windows per un determinato thread .NET.

Vedi la risposta del configuratore per ulteriori motivi per cui questo è il caso.


ATTENZIONE Con ​​.Net Core 2.2, si noti che AppDomain.GetCurrentThreadId (ho invocato tramite MethodInfo come obsoleto) restituisce l'ID del thread gestito (inutile per la corrispondenza di Process.GetCurrentProcess (). Raccolta thread.
brewmanz

32

Per ottenere l'ID del sistema operativo utilizzare:

AppDomain.GetCurrentThreadId()

1
GetHashCode non è necessariamente unico! e non dovrebbe usarlo per identificare un thread.
Dror Helper,

2
È possibile utilizzare AppDomain.GetCurrentThreadId () se si desidera l'ID del thread del sistema operativo, ma in teoria più thread .NET potrebbero in teoria condividere lo stesso thread del sistema operativo. Thread.GetHashCode () è garantito per restituire un valore unico a livello di processo, che è probabilmente quello che desideri.
Mark Byers,

3
Il metodo è contrassegnato come obsoleto e con buone ragioni. Si prega di vedere la mia risposta e configuratore per l'immagine più completa.
Paul Turner,

3
Bene, questo è l'unico modo per accedere all'ID thread del sistema operativo. E questo dovrebbe essere contrassegnato come la risposta corretta. Anche se non ho più intenzione di fare affidamento su questo.
LolaRun,

1
AppDomain.GetCurrentThreadId()è obsoleto: AppDomain.GetCurrentThreadId è stato deprecato perché non fornisce un ID stabile quando i thread gestiti sono in esecuzione fibers (aka lightweight threads). Per ottenere un identificatore stabile per un thread gestito, utilizzare la ManagedThreadIdproprietà su Thread. Utilizzo:Thread.CurrentThread.ManagedThreadId
Lijo Joseph

22

Secondo MSDN :

Un ThreadId del sistema operativo non ha una relazione fissa con un thread gestito, poiché un host non gestito può controllare la relazione tra thread gestiti e non gestiti. In particolare, un host sofisticato può utilizzare l'API di hosting CLR per pianificare molti thread gestiti sullo stesso thread del sistema operativo o per spostare un thread gestito tra thread del sistema operativo diversi.

Quindi, sostanzialmente, l' Threadoggetto non corrisponde necessariamente a un thread del sistema operativo, motivo per cui non ha l'ID nativo esposto.


La finestra Debug / Thread in VS2010 mostra "ID thread gestito". Come posso ottenere questo?
Pavel Radzivilovsky,

1
Utilizzare la proprietà ManagedThreadID msdn.microsoft.com/en-us/library/… . Questo non è lo stesso dell'ID thread del sistema operativo però.
configuratore

15

Per coloro che stanno per hackerare:

    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

Per trovare l'ID thread corrente utilizzare - `Thread.CurrentThread.ManagedThreadId '. Ma in questo caso potresti aver bisogno dell'attuale ID thread win32 - usa pInvoke per ottenerlo con questa funzione:

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

Per prima cosa dovrai salvare l'ID thread gestito e la connessione ID thread win32: usa un dizionario che associa un ID win32 al thread gestito.

Quindi, per trovare un thread con il suo id, iterare sul thread del processo usando Process.GetCurrentProcess (). Thread e trovare il thread con quell'id:

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

Credo che l'OP richieda l'ID del sistema operativo del thread, che non è lo stesso dell'ID del thread gestito.
Brian Rasmussen,

Questo codice non funziona: Process.Threads restituisce una raccolta di ProcessThreadoggetti, non è la stessa di (né eredita) Thread: (thread as Thread)restituirà un riferimento null.
Fredrik Mörk,

Ho notato che il codice del codice presentava alcuni bug - risolto provalo ora
Dror Helper

1
Ho finito per usare un dizionario che associa un id win32 a un thread gestito.
Contango,

11

L'offset in Windows 10 è 0x022C (applicazione x64-bit) e 0x0160 (applicazione x32-bit):

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
Funziona anche con Windows 7 x64 con SP1. Non raccomandato però. Utilizzare solo nei test temporanei.
guan boshen

5

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId

5

Dal codice gestito hai accesso alle istanze del Threadtipo per ogni thread gestito.Threadincapsula il concetto di thread del sistema operativo e, a partire dall'attuale CLR, esiste una corrispondenza uno a uno con thread gestiti e thread del sistema operativo. Tuttavia, questo è un dettaglio di implementazione, che potrebbe cambiare in futuro.

L'ID visualizzato da Visual Studio è in realtà l'ID del thread del sistema operativo. Questo non lo è lo stesso dell'ID del thread gestito come suggerito da diverse risposte.

Il Threadtipo include un campo membro IntPtr privato chiamato DONT_USE_InternalThread, che punta alla struttura del sistema operativo sottostante. Tuttavia, poiché si tratta in realtà di un dettaglio di attuazione, non è consigliabile perseguire questa IMO. E il nome indica che non dovresti fare affidamento su questo.


Per usare GetThreadId avresti bisogno dell'handle, che ottieni dal campo DONT_USE.
configuratore

Lo so, ma come ho detto, non puoi davvero contare sul fatto che i thread gestiti vengono mappati direttamente ai thread del sistema operativo, quindi non ci contare.
Brian Rasmussen,

Grazie mille per il chiarimento e per aver riassunto il problema. Ma ora se più thread gestiti possono corrispondere a un singolo thread del sistema operativo (come affermato dal configuratore - e viene ringraziato), ciò significa che VS mostra i thread del sistema operativo e non i thread gestiti.
LolaRun,

@OhrmaZd: Sì, VS2005 / 2008 mostra gli ID OS per i thread gestiti nella finestra Thread. VS2010B2 mostra effettivamente sia il sistema operativo che l'ID gestito per thread.
Brian Rasmussen,

@Brian Rasmussen: ora questa è un'identificazione per un thread gestito! Grazie per avere condiviso le tue conoscenze.
LolaRun,

4

È possibile utilizzare Thread.GetHashCode, che restituisce l'ID thread gestito. Se si pensa allo scopo di GetHashCode, questo ha senso: deve essere un identificatore univoco (ad es. Chiave in un dizionario) per l'oggetto (il thread).

La fonte di riferimento per la classe Thread è istruttiva qui. (Concesso, una particolare implementazione .NET può non essere basata su questo codice sorgente, ma per scopi di debug prenderò le mie possibilità.)

GetHashCode "fornisce questo codice hash per algoritmi che necessitano di controlli rapidi dell'uguaglianza degli oggetti", quindi è adatto per verificare l'uguaglianza dei thread, ad esempio per affermare che un particolare metodo è in esecuzione sul thread da cui si desidera venga chiamato.


4
Fantastico, ho appena aperto questa domanda di 5 anni per un'ora, sono tornato e ho visto "1 nuova risposta a questa domanda": D
Ray

Questa risposta è stata accennata in un altro commento, ma è stato quello che ho finito per usare dopo ulteriori ricerche. Forse non quello che voleva l'OP. Probabilmente all'OP non importa più. Potrebbe essere utile a qualcun altro. (E almeno in base alla fonte di riferimento, questo potrebbe essere il modo più efficiente per ottenere l'ID del thread.)
yoyo

bene, in questo momento mi trovo in un campo diverso, ma allora avevamo due ID per un thread, l'id del thread nativo e un ID per il thread gestito, e uno appartiene a un altro ... Principalmente, il Gli ID hanno lo scopo di identificare i thread, i GetHashCodes hanno un'altra utilità e possono scontrarsi. Gli sviluppatori di framework non avrebbero implementato un ID se avessimo dovuto utilizzare GetHashCode
LolaRun

3
@yoyo Le collisioni non interrompono l'uso del dizionario. Sono progettati per avere una bassa probabilità di collisione, non alcuna collisione. Se si esegue l'hashing di un valore di 128 bit su un valore di 64 bit, ogni valore di hash avrà circa 2 ^ 64 collisioni. Il dizionario è progettato per avere un algoritmo di fallback quando si verifica una collisione nel raro caso che accade.
bradgonesurfing,

2
@bradgonesurfing Hai perfettamente ragione e il mio commento precedente è sbagliato. Le prestazioni del dizionario diminuiranno con le collisioni di hash, ma la funzionalità rimane corretta. Mi scuso per il commento fuorviante, grazie per averlo sottolineato.
yoyo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.