Obtendo o ID do Encadeamento de um Encadeamento


319

Em C # ao depurar threads, por exemplo, você pode ver a identificação de cada thread.

Não consegui encontrar uma maneira de obter o mesmo segmento, programaticamente. Eu não conseguia nem obter o ID do segmento atual (nas propriedades do Thread.currentThread).

Então, eu me pergunto como o Visual Studio obtém os IDs dos threads e existe uma maneira de obter o identificador do thread com a ID 2345, por exemplo?

Respostas:


437

GetThreadIdretorna o ID de um determinado segmento nativo. Existem maneiras de fazê-lo funcionar com threads gerenciados, tenho certeza, tudo que você precisa encontrar é o identificador de thread e passá-lo para essa função.

GetCurrentThreadId retorna o ID do encadeamento atual.

GetCurrentThreadIdfoi preterido no .NET 2.0: a maneira recomendada é a Thread.CurrentThread.ManagedThreadIdpropriedade


87
Desde que eu encontrei isso, digitada, e, em seguida, foi dito que era Reprovado, a forma atual de fazer isso é Thread.CurrentThread.ManagedThreadId
James

3
ManagedThreadId não é uma abordagem robusta para identificar threads, pois os IDs de propriedade ManagedThreadId são reutilizados pelo seu aplicativo. Portanto, não é um identificador confiável para threads em alguns cenários e você experimentará a exceção: "Um item com a mesma chave já foi adicionado". na linha ... Atribua um nome exclusivo ao segmento quando você o criar.
Forer

15
Há alguns conselhos muito ruins por aí neste post. Algumas pessoas estão recomendando o uso de "ManagedThreadId" para identificar um thread. Editei o post para remover a recomendação - o que poucos apontaram é que existem diferentes tipos de IDs de threads. Os IDs de encadeamentos gerenciados não são a mesma coisa que os IDs de encadeamentos não gerenciados, e se as pessoas copiarem e colarem esse código, poderão ocorrer alguns bugs de sincronização muito sutis. A documentação no MSDN para a classe Thread é muito clara sobre isso. Veja as observações no nível da classe.
ShadowChaser

3
Você não sincroniza nos IDs, usa primitivas de sincronização como mutexes. Isso é apenas para fins de depuração.
Blindy

11
Eu gostaria de postar este comentário para perceber que System.Threading.Thread.CurrentThread.ManagedThreadIdnão funcionará pelo menos ao usar em um arquivo SetWindowsHookEx. Em vez disso, precisamos obter o ID do thread da função win32 nativa GetCurrentThreadId().
King King

82

Em C # ao depurar threads, por exemplo, você pode ver a identificação de cada thread.

Esses serão os IDs dos encadeamentos gerenciados. ManagedThreadIdé um membro Threadpara que você possa obter o ID de qualquer objeto Thread . Isso fornecerá o ManagedThreadID atual :

Thread.CurrentThread.ManagedThreadId

Para obter um encadeamento do SO com o ID do encadeamento do SO (não ManagedThreadID) , você pode tentar um pouco de linq.

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

Parece que não há como enumerar os threads gerenciados e nenhuma relação entre ProcessThread e Thread, portanto, obter um thread gerenciado por seu ID é difícil.

Para obter mais detalhes sobre o encadeamento gerenciado x não gerenciado, consulte este artigo do MSDN .


4
Por que ninguém mais apresentou essa resposta simples?
precisa

2
Isso não funciona. GetCurrentProcess (). Threads retorna um ProcessThreadCollection, que não é conversível em Threads. Não vejo uma solução fácil.
Mafu

2
@ mafutrct, resposta atualizada. Essa propriedade deve realmente ser chamada de .ProcessThreads! Obrigado.
precisa saber é o seguinte

2
Recomenda que esta postagem seja reescrita para deixar mais claro que os dois IDs de encadeamento são diferentes. Se alguém não conseguir ler a última frase, apenas conectará ManagedThreadId e tentará mapeá-la contra ProcessThread.Id, causando estragos.
ShadowChaser

1
Adicionei um link para um artigo útil do MSDN destacando a diferença. No entanto, a questão estava relacionada à obtenção do ID do segmento para depuração (que nesse caso é o ManagedThreadID). Não acho que a resposta com detalhes da diferença entre SO e threads gerenciados seja útil.
badbod99

46

Você pode usar o obsoleto AppDomain.GetCurrentThreadIdpara obter o ID do encadeamento atualmente em execução. Este método usa um PInvoke para o método API Win32 GetCurrentThreadIDe retornará a identificação de thread do Windows.

Esse método está marcado como descontinuado porque o objeto .NET Thread não corresponde a um único thread do Windows e, como tal, não existe um ID estável que possa ser retornado pelo Windows para um determinado thread do .NET.

Consulte a resposta do configurador para obter mais razões pelas quais esse é o caso.


CUIDADO Com .Net núcleo 2.2, nota que AppDomain.GetCurrentThreadId (I invocado via MethodInfo como obsoleto) retorna o ID thread gerenciado (inútil para combinar Process.GetCurrentProcess () Threads coleção..
brewmanz

32

Para obter o ID do sistema operacional, use:

AppDomain.GetCurrentThreadId()

1
GetHashCode não é necessariamente único! e não deve usá-lo para identificar um segmento.
Dror Helper

2
Você pode usar AppDomain.GetCurrentThreadId () se desejar o ID do encadeamento do SO, mas vários encadeamentos .NET poderiam, em teoria, compartilhar o mesmo encadeamento do SO. É garantido que Thread.GetHashCode () retorne um valor exclusivo para todo o processo, que é o que você provavelmente deseja.
Mark Byers

3
O método está marcado como obsoleto e por boas razões. Consulte minha resposta e o configurador para obter uma imagem mais completa.
Paul Turner

3
Bem, esta é a única maneira de obter o ID do segmento do SO. E isso deve ser marcado como a resposta correta. Mesmo que eu não vou mais confiar nisso.
LolaRun 5/11/2009

1
AppDomain.GetCurrentThreadId()está obsoleto: AppDomain.GetCurrentThreadId foi descontinuado porque não fornece um ID estável quando os threads gerenciados estão em execução fibers (aka lightweight threads). Para obter um identificador estável para um segmento gerenciado, use a ManagedThreadIdpropriedade no Thread. Uso:Thread.CurrentThread.ManagedThreadId
Lijo Joseph

22

De acordo com o MSDN :

Um ThreadId do sistema operacional não possui um relacionamento fixo com um encadeamento gerenciado, porque um host não gerenciado pode controlar o relacionamento entre os encadeamentos gerenciados e não gerenciados. Especificamente, um host sofisticado pode usar a API de hospedagem do CLR para agendar muitos threads gerenciados no mesmo thread do sistema operacional ou para mover um thread gerenciado entre diferentes threads do sistema operacional.

Então, basicamente, o Threadobjeto não corresponde necessariamente a um encadeamento do SO - e é por isso que não tem o ID nativo exposto.


A janela Debug / Threads no VS2010 mostra "ID do thread gerenciado". Como posso obter este?
Pavel Radzivilovsky

1
Use a propriedade ManagedThreadID msdn.microsoft.com/en-us/library/… . Porém, isso não é o mesmo que o ID do encadeamento do SO.
Configurator

15

Para quem está prestes a invadir:

    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

Para encontrar o ID do segmento atual, use - `Thread.CurrentThread.ManagedThreadId '. Mas, neste caso, você pode precisar do atual ID do thread do win32 - use o pInvoke para obtê-lo com esta função:

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

Primeiro, você precisará salvar a identificação do segmento gerenciado e a conexão do ID do segmento win32 - use um dicionário que mapeie um ID do win32 para o segmento gerenciado.

Em seguida, para localizar um segmento, ele identifica o segmento do processo usando Process.GetCurrentProcess (). Threads e encontra o segmento com esse ID:

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

Acredito que o OP esteja solicitando o ID do sistema operacional do encadeamento, que não é o mesmo que o ID do encadeamento gerenciado.
Brian Rasmussen

Este código não funciona: Process.Threads retorna uma coleção de ProcessThreadobjetos, não é o mesmo que (nem herda) Thread: (thread as Thread)retornará uma referência nula.
Fredrik Mörk

Tenho notado que o código de código tinha alguns erro - fixa-lo experimentá-lo agora
Dror Helper

1
Acabei usando um dicionário que mapeia uma identificação win32 para um thread gerenciado.
Contango 20/08/2012

11

O deslocamento no Windows 10 é 0x022C (aplicativo de 64 bits) e 0x0160 (aplicativo de 32 bits):

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
Funciona no Windows 7 x64 com SP1 também. Não é recomendado. Use apenas em testes temporários.
guan Boshen

5

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId

5

No código gerenciado, você tem acesso a instâncias do Threadtipo para cada encadeamento gerenciado. Threadencapsula o conceito de um encadeamento do SO e, no CLR atual, há uma correspondência individual com encadeamentos gerenciados e encadeamentos do SO. No entanto, este é um detalhe de implementação, que pode mudar no futuro.

O ID exibido pelo Visual Studio é realmente o ID do encadeamento do SO. Esta é não o mesmo que o ID thread gerenciado como sugerido por várias respostas.

O Threadtipo inclui um campo de membro IntPtr particular chamado DONT_USE_InternalThread, que aponta para a estrutura do SO subjacente. No entanto, como esse é realmente um detalhe de implementação, não é aconselhável buscar essa OMI. E o nome indica que você não deve confiar nisso.


Para usar GetThreadId, você precisará do identificador - obtido no campo DONT_USE.
Configurator

Eu sei, mas como eu disse, você realmente não pode contar com o fato de que os threads gerenciados mapeiam diretamente para os threads do SO, portanto, eu não contaria com isso.
Brian Rasmussen

Muito obrigado pelo esclarecimento e por resumir o problema. Mas agora, se vários threads gerenciados podem corresponder a um único thread do SO (como o configurador declarou - e ele agradeceu), isso significa que o VS está mostrando threads do SO e não Threads Gerenciados.
LolaRun

@OhrmaZd: Sim, o VS2005 / 2008 mostra IDs de SO para threads gerenciados na janela Threads. O VS2010B2 realmente mostra o SO e o ID gerenciado por encadeamento.
Brian Rasmussen

@ Brian Rasmussen: Agora isso é uma identificação para um segmento gerenciado! Obrigado por compartilhar o seu conhecimento.
LolaRun 5/11

4

Você pode usar Thread.GetHashCode, que retorna o ID do thread gerenciado. Se você pensa no objetivo de GetHashCode, isso faz sentido - ele precisa ser um identificador exclusivo (por exemplo, chave em um dicionário) para o objeto (o encadeamento).

A fonte de referência para a classe Thread é instrutiva aqui. (Concedido, uma implementação .NET específica pode não se basear nesse código-fonte, mas para fins de depuração, arrisco-me.)

GetHashCode "fornece esse código de hash para algoritmos que precisam de verificações rápidas da igualdade de objetos", portanto, é adequado para verificar a igualdade de threads - por exemplo, para afirmar que um método específico está sendo executado no thread do qual você deseja que ele seja chamado.


4
Incrível, eu só tive essa pergunta de 5 anos em aberto por uma hora, voltei e vi "1 nova resposta a esta pergunta": D
Ray

Essa resposta foi sugerida em outro comentário, mas foi o que acabei usando após algumas pesquisas. Possivelmente não o que o OP queria. Provavelmente o OP não se importa mais. Pode ser útil para outra pessoa. (E, pelo menos com base na fonte de referência, esta pode ser a maneira mais eficiente para obter o ID da thread.)
yoyo

bem, eu estou em um campo diferente agora, mas naquela época tínhamos dois IDs para um thread, o id do thread nativo e um id para o thread gerenciado, e um pertence a outro ... Principalmente, o Os IDs têm como objetivo identificar os threads, GetHashCodes tem outro utilitário e podem colidir. Desenvolvedores quadro não teria aplicado um ID se tivéssemos que usar GetHashCode
LolaRun

3
As colisões do @yoyo não quebram o uso do dicionário. Eles são projetados para ter uma baixa probabilidade de colisão, e nenhuma colisão. Se você hash um valor de 128 bits para um valor de 64 bits, todo valor de hash terá aproximadamente 2 ^ 64 colisões. O dicionário foi projetado para ter um algoritmo de fallback quando uma colisão ocorre nos raros casos em que ocorre.
Bradgonesurfing

2
@bradgonesurfing Você está absolutamente certo, e meu comentário anterior está errado. O desempenho do dicionário diminuirá com colisões de hash, mas a funcionalidade permanece correta. Peço desculpas pelo comentário enganador, obrigado por apontar isso.
yoyo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.