在C#中,例如在调试线程时,可以看到每个线程的ID。
我找不到一种程序化地获取相同线程的方法。我甚至无法获取当前线程的ID(在Thread.currentThread
的属性中)。
那么,我想知道Visual Studio如何获取线程的ID,并且是否有一种方法可以获取ID为2345
的线程的句柄?
在C#中,例如在调试线程时,可以看到每个线程的ID。
我找不到一种程序化地获取相同线程的方法。我甚至无法获取当前线程的ID(在Thread.currentThread
的属性中)。
那么,我想知道Visual Studio如何获取线程的ID,并且是否有一种方法可以获取ID为2345
的线程的句柄?
GetThreadId
函数返回给定本地线程的 ID。我确信有办法使其适用于托管线程,你只需要找到线程句柄并将其传递给该函数即可。
对于托管线程,请使用System.Environment.CurrentManagedThreadId
。
以下是旧 SDK 选项,但首选使用 System.Environment.CurrentManagedThreadId
.
GetCurrentThreadId
函数返回当前线程的 ID。自 .NET 2.0 起已弃用 GetCurrentThreadId
。Thread.CurrentThread.ManagedThreadId
返回当前托管线程的唯一标识符,与 System.Environment.CurrentManagedThreadId
相同,然而,System.Environment.CurrentManagedThreadId
更受推荐 (CA1840)。在C#中,例如调试线程时,可以看到每个线程的ID。
这些将是托管线程的ID。 ManagedThreadId
是 Thread
的成员,因此您可以从任何 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线程,因此没有稳定的ID可以由Windows针对给定的.NET线程返回。
有关此情况的更多原因,请参见configurator的答案。
获取操作系统 ID 的方法如下:
AppDomain.GetCurrentThreadId()
AppDomain.GetCurrentThreadId()
is obsolete: AppDomain.GetCurrentThreadId
has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads)
. To get a stable identifier for a managed thread, use the ManagedThreadId
property on Thread
.Usage: Thread.CurrentThread.ManagedThreadId
- L J因此,基本上操作系统的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;
}
[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)
将返回一个空引用。 - Fredrik Mörk在Windows 10下,x64位应用程序的偏移量为0x022C,x32位应用程序的偏移量为0x0160:
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.Environment.CurrentManagedThreadId
替换Thread.CurrentThread.ManagedThreadId
。
System.Environment.CurrentManagedThreadId
是Thread.CurrentThread.ManagedThreadId
模式的一种紧凑高效的替代方式。
从托管代码中,您可以访问每个托管线程的Thread
类型实例。 Thread
封装了操作系统线程的概念,在当前CLR中,托管线程和操作系统线程是一对一的对应关系。但是,这是一个实现细节,未来可能会发生变化。
Visual Studio显示的ID实际上是操作系统线程ID。这与几个回复建议的托管线程ID不同。
Thread
类型确实包括一个名为DONT_USE_InternalThread
的私有IntPtr成员字段,它指向底层的操作系统结构。然而,由于这只是一个实现细节,所以我认为不建议追求此项。而且该名称表明您不应依赖此项。
SetWindowsHookEx
中使用时,System.Threading.Thread.CurrentThread.ManagedThreadId
至少不起作用。相反,我们必须从本机win32函数GetCurrentThreadId()
中获取线程ID。 - King King