在
Java中,可以重命名线程.在.NET中不是.这是因为Name是一个在Thread类中一次写入的属性:
public string Name { get { return this.m_Name; } [HostProtection(SecurityAction.LinkDemand,ExternalThreading=true)] set { lock (this) { if (this.m_Name != null) { throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WriteOnce")); } this.m_Name = value; InformThreadNameChangeEx(this,this.m_Name); } } }
鉴于Java允许线程重命名,并且使用的大多数底层线程结构都是在两个平台上都是操作系统提供的,所以我倾向于认为我可以在C#中重命名一个线程,如果我避免了一组功能,)我不在乎,或b)根本不使用.
你有什么想法为什么线程重命名是一次写入操作?任何改变名字的想法都会打破什么?
我已经尝试过一个测试,我重命名线程:
var t1 = new Thread(TestMethod); t1.Name = "abc"; t1.Start(); t1.GetType().GetField("m_Name",BindingFlags.Instance | BindingFlags.NonPublic).SetValue(t1,"def"); t1.GetType().GetMethod("InformThreadNameChangeEx",BindingFlags.NonPublic | BindingFlags.Static).Invoke(t1,new object[] { t1,t1.Name});
结果是名字的确改变了,这反映在使用这个线程的其他代码上.这样做的背景是,我需要记录线程所做的事情,我使用的日志库(log4net)使用Thread.Name来指定哪个线程做什么动作.提前致谢.
编辑:请停止建议明显的事情!如果我问如何重新命名,我知道如何在开始时命名一个线程.
我需要这样做的原因是线程将被重新使用,它可能被另一个组件使用,我想表示这一点,如果和什么时候会发生日志记录,以便具有特定的线程名称,而不是通用号码.
解决方法
我使用
Reflector的分析操作,我看到(或更确切地说Nikolaos看到)使用Thread.Name getter的唯一代码是在user32.dll中调用RegisterClassEx API. Thread类本身只引用Name getter和setter中的m_Name成员.我怀疑以您采用的方式重命名线程是安全的.除了我将更改您的代码以获取与Thread.Name将具有的同一对象上的锁.幸运的是,这不过是Thread实例本身,所以很容易做到.
var t1 = new Thread(TestMethod); t1.Name = "abc"; t1.Start(); lock (t1) { t1.GetType(). GetField("m_Name",BindingFlags.Instance | BindingFlags.NonPublic). SetValue(t1,"def"); t1.GetType(). GetMethod("InformThreadNameChangeEx",BindingFlags.NonPublic | BindingFlags.Static). Invoke(t1,t1.Name}); }
另外需要注意的是,根据应用程序的信任级别,您可能会遇到代码访问安全性和私有成员更改的问题.显然,这似乎并没有在你的测试中发挥作用,但值得一提的是这里.