从线程获取线程ID

Lol*_*Run 304 .net c# multithreading

例如,在调试线程的C#中,您可以看到每个线程的ID.

我无法通过编程方式找到获得相同线程的方法.我甚至无法获得当前线程的ID(在属性中Thread.currentThread).

所以,我想知道Visual Studio如何获取线程的ID,并且有没有办法获取带有id的线程的句柄2345,例如?

Bli*_*ndy 422

GetThreadId返回给定本机线程的ID.有一些方法可以使它与托管线程一起使用,我敢肯定,您需要找到的只是线程句柄并将其传递给该函数.

GetCurrentThreadId 返回当前线程的ID.

GetCurrentThreadId自.NET 2.0起已被弃用:推荐的方法是Thread.CurrentThread.ManagedThreadId属性.

  • 既然我发现了这个,输入它,然后被告知它是Deprecated,目前这样做的方法是Thread.CurrentThread.ManagedThreadId (84认同)
  • 在这篇文章中有一些非常糟糕的建议.有些人建议使用"ManagedThreadId"来识别线程.我编辑了帖子以删除建议 - 很少有人指出有不同类型的线程ID.托管线程ID与非托管线程ID不同,如果人们要复制并粘贴该代码,则可能会发生一些非常微妙的同步错误.关于Thread类的MSDN文档非常清楚.查看班级的评论. (14认同)
  • 我想发表这个评论,注意到`System.Threading.Thread.CurrentThread.ManagedThreadId`至少在使用`SetWindowsHookEx`时不起作用.相反,我们必须从本机win32函数`GetCurrentThreadId()`获取线程id. (11认同)
  • ManagedThreadId不是一种强大的方法来识别线程,因为ManagedThreadId属性id会被您的应用程序重用.因此,在某些情况下,它不是线程的可靠标识符,您将遇到异常:"已添加具有相同键的项目." at line ...在创建时给线程一个唯一的名称. (3认同)
  • 虽然您没有在ID上进行同步,但您使用的是同步原语,例如互斥锁.这仅用于调试目的. (3认同)

bad*_*d99 76

例如,在调试线程的C#中,您可以看到每个线程的ID.

这将是托管线程的ID. ManagedThreadId是一个成员,Thread所以你可以从任何Thread对象获取Id .这将获得当前的ManagedThreadID:

Thread.CurrentThread.ManagedThreadId
Run Code Online (Sandbox Code Playgroud)

要通过它的OS线程ID (而不是ManagedThreadID)来获取OS线程,您可以尝试一些linq.

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

似乎没有办法枚举托管线程并且没有ProcessThread和Thread之间的关系,因此通过它的Id获取托管线程是一个艰难的.

有关托管与非托管线程的更多详细信息,请参阅此MSDN arcticle.

  • 为什么没有其他人提出这个简单的答案? (4认同)
  • 这不起作用.GetCurrentProcess().Threads返回一个ProcessThreadCollection,它不能转换为Threads.我没有看到一个简单的解决方案. (2认同)
  • @ mafutrct,更新回答.应该真正调用该属性.ProcessThreads!谢谢. (2认同)
  • 建议将此帖子改写,以使两个线程ID更加清楚。如果有人看不懂最后一句话,他们只会插入ManagedThreadId并尝试将其映射到ProcessThread.Id,从而创建havok。 (2认同)

Pau*_*ner 44

您可以使用deprecated AppDomain.GetCurrentThreadId来获取当前正在运行的线程的ID.此方法使用PInvoke到Win32 API方法GetCurrentThreadID,并将返回Windows线程ID.

此方法被标记为已弃用,因为.NET Thread对象不对应于单个Windows线程,因此没有稳定的ID可由Windows为给定的.NET线程返回.

请参阅配置程序的答案,了解更多原因.

  • 注意对于 .Net Core 2.2,请注意 AppDomain.GetCurrentThreadId(我通过 MethodInfo 作为 Obsolete 调用)返回托管线程 ID(对于匹配 Process.GetCurrentProcess().Threads 集合无用。 (3认同)

Mar*_*ers 31

要获取操作系统ID,请使用:

AppDomain.GetCurrentThreadId()
Run Code Online (Sandbox Code Playgroud)

  • 那么这是获得操作系统线程ID的唯一方法.这应该被标记为正确的答案.即使我不再依赖这个了. (3认同)
  • 如果你想要OS线程ID,你可以使用AppDomain.GetCurrentThreadId(),但理论上多个.NET线程可以共享相同的OS线程.Thread.GetHashCode()保证返回一个唯一的进程范围的值,这是你可能想要的. (2认同)
  • 该方法被标记为已弃用,并且有充分的理由.请查看我的答案和配置器以获得更全面的图片. (2认同)

con*_*tor 21

根据MSDN:

操作系统ThreadId与托管线程没有固定的关系,因为非托管主机可以控制托管和非托管线程之间的关系.具体而言,复杂的主机可以使用CLR Hosting API针对同一操作系统线程调度许多托管线程,或者在不同操作系统线程之间移动托管线程.

所以基本上,该Thread对象不一定对应于OS线程 - 这就是为什么它没有暴露本机ID的原因.


ezo*_*tko 14

对于那些即将入侵的人:

    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;
    }
Run Code Online (Sandbox Code Playgroud)


Dro*_*per 10

要查找当前线程Id,请使用 - "Thread.CurrentThread.ManagedThreadId".但在这种情况下,您可能需要当前的win32线程ID - 使用pInvoke来获取此函数:

[DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
public static extern Int32 GetCurrentWin32ThreadId();
Run Code Online (Sandbox Code Playgroud)

首先,您需要保存托管线程ID和win32线程ID连接 - 使用将win32 id映射到托管线程的字典.

然后通过它的id找到一个线程使用Process.GetCurrentProcess()迭代进程的线程.线程并找到具有该id的线程:

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


小智 10

Windows 10下的偏移量为0x022C(x64位应用程序)和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;
}
Run Code Online (Sandbox Code Playgroud)


Ric*_*h K 8

截至 2022 年 7 月,VS2022 IDE 建议使用System.Environment.CurrentManagedThreadId而不是Thread.CurrentThread.ManagedThreadId

引用自https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1840

System.Environment.CurrentManagedThreadId 是 Thread.CurrentThread.ManagedThreadId 模式的紧凑且高效的替代方案。


Man*_*anu 5

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId
Run Code Online (Sandbox Code Playgroud)


Bri*_*sen 5

从托管代码中,您可以访问Thread每个托管线程的类型实例.Thread封装了OS线程的概念,并且在当前CLR中,与托管线程和OS线程一一对应.但是,这是一个实现细节,可能在将来发生变化.

Visual Studio显示的ID实际上是OS线程ID.这是一样的托管线程ID几种答复的建议.

Thread类型确实包含一个名为的私有IntPtr成员字段DONT_USE_InternalThread,该字段指向底层的OS结构.但是,由于这实际上是一个实施细节,因此不宜采用这种IMO.名称有点表明你不应该依赖于此.