如何在没有AppDomain.GetCurrentThreadId()的情况下获取当前线程id,使其实际工作

本文关键字:线程 前线 获取 id 实际工作 情况下 AppDomain GetCurrentThreadId | 更新日期: 2023-09-27 18:19:35

由于AppDomin.GetCurrentThreadId()是过时的

"AppDomain.GetCurrentThreadId已被弃用,因为它没有当托管线程在光纤上运行时提供稳定的Id(aka轻质螺纹)。为了获得托管线程的稳定标识符,对Thread使用ManagedThreadId属性。http://go.microsoft.com/fwlink/?linkid=14202"

我试着不使用它。但是,解释"Thread.CurrentThread.ManagedThreadId"会起作用是没有价值的,因为它没有提供Win32线程id,而我需要它来进行Win32调用。所以我自己实现了如下。

public sealed class AppDomainExtender
{
    public static int GetCurrentThreadId_New()
    {
        return Process.GetCurrentProcess().Threads.OfType<ProcessThread>().SingleOrDefault(x => x.ThreadState == System.Diagnostics.ThreadState.Running).Id;
    }
}

现在有两个问题。

  • 如果它能工作,它不会和AppDomain.GetCurrentThreadId完全一样吗
  • 它不起作用,因为在SingleOrDefault循环中循环时,运行的线程可能会发生变化。这种行为很奇怪,但它只是给我带来了一个InvalidOperationException("Sequence包含多个元素")。例如,当使用多个桌面时,似乎会发生这种情况(我认为这只有通过将执行循环的线程复制到另一个id才能实现)

问题:

  1. AppDomain.GetCurrentThreadId是否被错误地声明为过时
  2. 如何使"Process.GetCurrentProcess().Threads.OfType().SingleOrDefault(x=>x.ThreadState==System.Diagnostics.ThreadState.Running).Id"这句话成为原子,或者这可能吗

如何在没有AppDomain.GetCurrentThreadId()的情况下获取当前线程id,使其实际工作

AppDomain.GetCurrentThreadId()的弃用是一个不方便的事实,当然不是一个"错误"声明。从.NET 2.0开始,.NET线程和操作系统线程之间的关联被破坏。自定义CLR主机可以自由地通过实现IClrTask接口以其认为合适的方式实现线程。换句话说,不能保证两个不同的.NET线程使用具有不同线程ID的不同操作系统线程。

在20世纪90年代和21世纪初,这通常是一种流行的做法,名称包括"轻量级线程"、协同例程、光纤、"绿色线程"等。其目的是避免操作系统切换线程上下文,而避免软件中CPU寄存器的上下文切换。SQL Server是该功能的主要受益者,它内置了对"光纤模式"的支持。

虽然SQL Server团队获得了该功能,但他们最终决定不发货。当他们无法使该项目足够稳定时,他们放弃了该项目。一个问题可能激发了这篇文章的灵感,这篇文章发表在他们项目到期的同一年。没有再次尝试。一点也不因为这个功能被多核革命所淘汰。在现代内核中,上下文切换的成本由CPU缓存的状态决定,不可能与每个拥有自己的L1和L2缓存的内核竞争。

我不知道有任何CLR主机真正实现了IClrTask,SQL Server团队的失败无疑是一个巨大的危险信号。然而,这并不排除这种可能性,您可能想担心的情况是在支持托管语言脚本的大型非托管应用程序的上下文中运行代码。CAD程序就是一个典型的例子。

非常不太可能的情况下,你会死在水里,你的代码实际上会在这种情况下运行,所以把你的激光设置为眩晕并继续前进。除了必须忍受过时警告之外,最明智的解决方法是pinvokeGetCurrentThreadId()。它非常快。