如何在没有AppDomain.GetCurrentThreadId()的情况下获取当前线程ID,以便它实际工作?

xam*_*mid 3 c# multithreading atomic appdomain

由于AppDomin.GetCurrentThreadId()已过时

"AppDomain.GetCurrentThreadId已被弃用,因为当托管线程在光纤(也称为轻量级线程)上运行时,它不提供稳定的Id.要获取托管线程的稳定标识符,请使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在有两个问题.

  • 如果它可以工作,它不会与AppDomain.GetCurrentThreadId完全相同吗?
  • 它不起作用的原因是在循环通过SingleOrDefault循环时正在运行的线程可能会发生变化.这种行为很奇怪,但它只是让我产生了一个InvalidOperationException("Sequence包含多个元素").显然它发生在例如使用多个桌面时(我假设这只能通过将执行循环的线程复制到另一个id来实现).

问题:

  1. AppDomain.GetCurrentThreadId是否被错误地声明为过时?
  2. 如何制作语句"Process.GetCurrentProcess().Threads.OfType().SingleOrDefault(x => x.ThreadState == System.Diagnostics.ThreadState.Running).Id"atomic,还是甚至可能?

Han*_*ant 10

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

这在20世纪90年代和21世纪初通常是一个流行的事情,通过名称如"轻量级线程",协同例程,光纤,"绿色线程"等.这个想法是避免线程上下文切换操作系统和上下文切换CPU在软件中注册.SQL Server是此功能的主要受益者,它内置支持"光纤模式".

当SQL Server团队获得该功能时,他们最终决定不发布它.当他们无法让它足够稳定时,他们放弃了这个项目.一个可能激发了这篇文章的问题,在同一年发布了他们的项目.这没有再次尝试.至少是因为该功能被多核革命淘汰了.现代核心中的上下文切换的成本由CPU高速缓存的状态决定,不可能与具有其自己的L1和L2高速缓存的每个核心竞争.

我不知道任何实际实现IClrTask的CLR主机,SQL Server团队的失败肯定是一个大红旗.但是,这并不排除这种可能性,您可能想要担心的一种情况是在支持托管语言脚本的大型非托管应用程序的上下文中运行代码.CAD程序就是典型的例子.

你会死在水中非常代码居然会在这种环境中运行不太可能的情况下,这样设置你的激光眩晕,锐意进取.除了不得不忍受过时警告之外,最安全的解决方法是使用GetCurrentThreadId().它非常快.