【发布时间】:2010-12-13 08:22:27
【问题描述】:
例如在 C# 中调试线程时,可以看到每个线程的 ID。
我找不到以编程方式获取相同线程的方法。我什至无法获得当前线程的 ID(在 Thread.currentThread 的属性中)。
所以,我想知道 Visual Studio 如何获取线程的 ID,有没有办法获取 ID 为 2345 的线程的句柄,例如?
【问题讨论】:
标签: c# .net multithreading
例如在 C# 中调试线程时,可以看到每个线程的 ID。
我找不到以编程方式获取相同线程的方法。我什至无法获得当前线程的 ID(在 Thread.currentThread 的属性中)。
所以,我想知道 Visual Studio 如何获取线程的 ID,有没有办法获取 ID 为 2345 的线程的句柄,例如?
【问题讨论】:
标签: c# .net multithreading
GetThreadId 返回给定本机线程的 ID。有办法让它与托管线程一起工作,我敢肯定,你只需要找到线程句柄并将其传递给该函数。
GetCurrentThreadId 返回当前线程的 ID。
GetCurrentThreadId 自 .NET 2.0 起已被弃用:推荐的方法是 Thread.CurrentThread.ManagedThreadId 属性。
【讨论】:
System.Threading.Thread.CurrentThread.ManagedThreadId 至少在SetWindowsHookEx 中使用时不起作用。相反,我们必须从本机 win32 函数 GetCurrentThreadId() 获取线程 ID。
例如在 C# 中调试线程时,可以看到每个线程的 ID。
这将是托管线程的 ID。 ManagedThreadId 是 Thread 的成员,因此您可以从任何 Thread 对象中获取 Id。这将为您提供当前的ManagedThreadID:
Thread.CurrentThread.ManagedThreadId
要通过 OS 线程 ID (不是 ManagedThreadID) 获取 OS 线程,您可以尝试一下 linq。
int unmanagedId = 2345;
ProcessThread myThread = (from ProcessThread entry in Process.GetCurrentProcess().Threads
where entry.Id == unmanagedId
select entry).First();
似乎没有办法枚举托管线程,并且 ProcessThread 和 Thread 之间没有关系,因此通过其 Id 获取托管线程是一个艰难的过程。
有关托管与非托管线程的更多详细信息,请参阅this MSDN article。
【讨论】:
您可以使用已弃用的AppDomain.GetCurrentThreadId 来获取当前正在运行的线程的ID。此方法对 Win32 API 方法GetCurrentThreadID 使用 PInvoke,并将返回 Windows 线程 ID。
此方法被标记为已弃用,因为 .NET 线程对象不对应于单个 Windows 线程,因此 Windows 无法为给定的 .NET 线程返回稳定的 ID。
请参阅配置者的回答了解更多原因。
【讨论】:
要获取操作系统 ID,请使用:
AppDomain.GetCurrentThreadId()
【讨论】:
AppDomain.GetCurrentThreadId() 已过时:AppDomain.GetCurrentThreadId 已被弃用,因为当托管线程在 fibers (aka lightweight threads) 上运行时,它不提供稳定的 Id。要获得托管线程的稳定标识符,请使用Thread 上的ManagedThreadId 属性。用法:Thread.CurrentThread.ManagedThreadId
根据MSDN:
操作系统的 ThreadId 没有 与托管的固定关系 线程,因为非托管主机可以 控制之间的关系 托管和非托管线程。 具体来说,一个复杂的主机可以 使用 CLR Hosting 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;
}
}
【讨论】:
ProcessThread对象的集合,这和Thread不一样(也不继承):(thread as Thread)会返回一个空引用.
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 封装了 OS 线程的概念,在当前的 CLR 中,托管线程和 OS 线程是一一对应的。但是,这是一个实现细节,将来可能会改变。
Visual Studio 显示的 ID 实际上是 OS 线程 ID。这不与多个回复所建议的托管线程 ID 相同。
Thread 类型确实包含一个名为 DONT_USE_InternalThread 的私有 IntPtr 成员字段,它指向底层 OS 结构。然而,由于这实际上是一个实施细节,因此不建议追求这个 IMO。这个名字有点表明你不应该依赖这个。
【讨论】:
您可以使用 Thread.GetHashCode,它返回托管线程 ID。如果您考虑 GetHashCode 的用途,这很有意义 - 它需要是对象(线程)的唯一标识符(例如字典中的键)。
reference source for the Thread class 在这里很有指导意义。 (当然,特定的 .NET 实现可能不是基于此源代码,但出于调试目的,我会抓住机会。)
GetHashCode“为需要快速检查对象相等性的算法提供此哈希码”,因此它非常适合检查线程相等性 - 例如断言特定方法正在您想要的线程上执行从调用。
【讨论】: