从线程中获取线程ID

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

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

所以,我想知道Visual Studio如何获得线程的id,并且有一种方法来获得线程的句柄与id 2345,例如?

378851 次浏览

获取操作系统ID使用:

AppDomain.GetCurrentThreadId()

System.Threading.Thread.CurrentThread.Name

System.Threading.Thread.CurrentThread.ManagedThreadId

GetThreadId返回给定本机线程的ID。有很多方法可以让它与托管线程一起工作,我相信,你只需要找到线程句柄并将它传递给那个函数。

GetCurrentThreadId返回当前线程的ID。

GetCurrentThreadId自。net 2.0起已弃用:建议使用Thread.CurrentThread.ManagedThreadId属性。

查找当前线程Id使用- ' thread . currentthread . managedthreadid '。 但在这种情况下,你可能需要当前的win32线程id -使用pInvoke通过这个函数来获得它:

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

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

然后使用process . getcurrentprocess()遍历进程的线程,通过线程的id找到线程。线程,并找到具有该id的线程:

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

从托管代码中,你可以访问每个托管线程的Thread类型的实例。Thread封装了操作系统线程的概念,目前的CLR与托管线程和操作系统线程是一一对应的。然而,这是一个实现细节,将来可能会改变。

Visual Studio显示的ID实际上是操作系统线程ID。这是,与几个回复所建议的托管线程ID相同。

Thread类型确实包含一个名为DONT_USE_InternalThread的私有IntPtr成员字段,它指向底层操作系统结构。然而,由于这实际上是一个实现细节,因此不建议继续执行这个IMO。这个名字暗示了你不应该依赖它。

根据MSDN:

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

.操作系统线程

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

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

此方法被标记为已弃用,因为. net Thread对象不对应于单个Windows线程,因此Windows无法为给定的. net线程返回稳定的ID。

关于为什么会出现这种情况的更多原因,请参阅配置器的答案。

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

这将是托管线程的id。ManagedThreadIdThread的成员,所以你可以从任何线程对象中获取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文章

对于那些想要入侵的人:

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

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

Thread类的引用源在这里很有指导意义。(当然,一个特定的。net实现五月不是基于这个源代码,但出于调试的目的,我会冒险。)

GetHashCode方法“为需要快速检查对象是否相等的算法提供了这个哈希代码”,所以它非常适合检查线程是否相等——例如,断言某个特定的方法正在你希望调用它的线程上执行。

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

截至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模式的紧凑而高效的替代。