如何为线程池中的每个新线程初始化标记为ThreadStaticAttribute的静态字段?

3

我有一个标记有 ThreadStaticAttribute 的字段。它在主线程中初始化,但我的代码使用了很多 async/await 结构和 Parallel 库,所以我不知道会执行多少个线程。我想确保每个线程都有这个字段被初始化。我该怎么做?


您可以在第一次访问时进行初始化(也就是说,当您想要读取值时,如果发现该字段尚未初始化,则进行初始化)。 - Evk
@Evk 在访问之前有没有任何初始化的方法? - Joseph Katzman
2
我不这么认为。实际上,初始化它是不被鼓励的,因为文档中指出:“不要为标记有ThreadStaticAttribute的字段指定初始值,因为这样的初始化仅在类构造函数执行时发生一次,因此仅影响一个线程”。我认为你可以使用ThreadLocal<T>来实现你想要的效果。 - Evk
3
还有一个名为“AsyncLocal<T>”的类,值得一看。 - Peit
@Evk:如果使用“类似单例”的初始化,不使用直接初始化,能否解决OP的问题(在访问之前进行初始化)? - Flater
@Flater 我认为这就是我在第一条评论中建议的。但仍需要先检查字段的值(以查看是否已初始化),但由于某种原因,OP想要避免这样做。 - Evk
1个回答

4

使用 ThreadStaticAttribute 时,您无法以您想要的方式执行初始化。实际上,文档指出您根本不应该执行任何初始化:

不要为标记有 ThreadStaticAttribute 的字段指定初始值,因为这种初始化仅在类构造函数执行时发生一次,因此仅影响一个线程

但是,您可以使用替代方案:ThreadLocal<T>

 private ThreadLocal<string> _myVar = new ThreadLocal<string>(() => "some string");

 var s = _myVar.Value; // separate for each thread
 _myVar.Value = "changed";

请注意,ThreadLocal<T> 实现了 IDisposable 接口,因此在使用完毕后必须进行处理。
您还可以为 ThreadStatic 字段实现单独的访问器,该访问器将首先检查字段是否已初始化,如果未初始化,则初始化它,然后返回值(类似于单例模式)。由于有 ThreadStatic 字段,因此可以在没有任何锁的情况下进行线程安全操作。
还要注意,使用 ThreadStaticThreadLocal 与线程池线程(如您所做)可能会导致意外行为,因为当线程返回到池中时,本地线程存储不会被清除。因此,您可能会“启动”一个新线程(而实际上是从池中取出线程),而该线程可能已经留下了来自前一次迭代的 ThreadStatic`ThreadLocal` 字段的值。

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