繁体   English   中英

从线程中获取线程 ID

[英]Getting the thread ID from a thread

以 C# 为例,在调试线程时,可以看到每个线程的 ID。

我找不到以编程方式获取相同线程的方法。 我什至无法获得当前线程的 ID(在Thread.currentThread的属性中)。

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

GetThreadId返回给GetThreadId机线程的 ID。 有很多方法可以使它与托管线程一起工作,我敢肯定,您只需要找到线程句柄并将其传递给该函数即可。

GetCurrentThreadId返回当前线程的 ID。

从 .NET 2.0 开始,不推荐使用GetCurrentThreadId :推荐的方法是Thread.CurrentThread.ManagedThreadId属性。

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

这将是托管线程的 ID。 ManagedThreadIdThread的成员,因此您可以从任何Thread对象获取 Id。 这将为您提供当前的ManagedThreadID

Thread.CurrentThread.ManagedThreadId

要通过其操作系统线程 ID (不是 ManagedThreadID)获取操作系统线程,您可以尝试一些 linq。

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

似乎无法枚举托管线程,并且 ProcessThread 和 Thread 之间没有关系,因此通过其 Id 获取托管线程是一项艰巨的任务。

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

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

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

有关出现这种情况的更多原因,请参阅配置器的回答。

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

AppDomain.GetCurrentThreadId()

根据MSDN

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

所以基本上, Thread对象不一定对应于操作系统线程 - 这就是它没有公开本机 ID 的原因。

对于那些即将入侵的人:

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

要查找当前线程 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;
     }
}

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

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId

从托管代码中,您可以访问每个托管线程的Thread类型实例。 Thread封装了操作系统线程的概念,从当前的 CLR 开始,托管线程和操作系统线程是一一对应的。 但是,这是一个实现细节,将来可能会发生变化。

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

Thread类型确实包括一个名为DONT_USE_InternalThread的私有 IntPtr 成员字段,它指向底层操作系统结构。 但是,由于这确实是一个实施细节,因此不建议遵循此 IMO。 这个名字有点表明你不应该依赖这个。

您可以使用 Thread.GetHashCode,它返回托管线程 ID。 如果您考虑 GetHashCode 的用途,这很有意义——它需要是对象(线程)的唯一标识符(例如字典中的键)。

Thread 类参考源在这里很有启发性。 (当然,特定的 .NET 实现可能不是基于此源代码,但出于调试目的,我会抓住机会。)

GetHashCode “为需要快速检查对象相等性的算法提供此哈希码”,因此它非常适合检查线程相等性——例如,断言特定方法正在您希望调用它的线程上执行。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM