当线程结束时,标记为C# ThreadStaticAttribute的字段会自动释放吗?

19

我发现了ThreadStaticAttribute,对它有很多问题:

我之前实现的所有线程相关静态信息都是作为一个静态字典来实现的,其中 TKey 是 Thread,当我想要访问它时,我使用了 Thread.CurrentThread,这样可以工作。但这需要维护,因为如果线程死掉了,我必须从字典中删除相应的条目。我还需要考虑线程安全和许多其他问题。

通过使用ThreadStaticAttribute,所有这些问题似乎都得到了解决,但我需要确信。我的问题是:在线程死亡之前,我需要删除由ThreadStaticAttribute标记的字段所持有的实例吗??该字段的信息保存在哪里??它保存在Thread对象的实例中,或者类似于这样的东西,以便在不再使用时,垃圾收集器自动丢弃它?是否存在性能惩罚?有什么影响?与我之前使用的基于键的集合相比,它是否更快?

我需要澄清ThreadStaticAttribute的工作原理。

2个回答

15

在被标记为ThreadStatic的字段中,您不需要删除帮助值实例。当线程和对象都不再被根对象引用时,垃圾回收器会自动回收它们。

唯一的例外是,如果该值实现了IDisposable并且您想要主动处理它,则需要删除。总的来说,由于多种原因,这是一个难以解决的问题。最简单的方法是不要在ThreadStatic字段中使用实现IDisposable的值。

至于这个字段实际存储在哪里,这有点无关紧要。您只需要关注它将像.NET中的任何其他对象一样运行即可。唯二的行为差异是:

  1. 该字段将针对每个访问线程引用不同的值。
  2. 该字段的初始化程序仅运行一次(在实践中,最好完全避免使用任何初始化器)。

6
将静态成员变量标记为 [ThreadStatic] 告诉编译器将其分配到线程的内存区域(例如,分配线程堆栈的位置)而不是全局内存区域中。因此,每个线程都将拥有自己的副本(这些副本保证初始化为该类型的默认值,例如 null、0、false 等;不要使用内联初始化程序,因为它们只会为一个线程初始化)。当线程消失时,它的内存区域也会释放引用。当然,如果需要更快地处理某些内容(例如打开的文件流等),而不是等待后台垃圾回收,您可能需要确保在线程退出之前进行处理。
[ThreadStatic] 空间的数量可能有限,但对于正常使用应该足够了。它应该比访问键控集合更快(并且更容易实现线程安全),我认为它与访问普通静态变量相当。
更正:我后来听说访问 ThreadStatic 变量比访问普通静态变量稍慢一些。我不确定它是否比访问键控集合更快,但它避免了孤立问题(这是您的问题),并且需要锁定以实现线程安全,这会使键控集合方法变得更加复杂。

3
编译器在ThreadStatic属性方面实际上什么也没做。它完全由CLR处理。 - JaredPar
好的,但是如果把“编译器”用比喻的意义来理解,而不是严格的字面意义,你就会明白如何使用这个属性了。 - Rob Parker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接