【问题标题】:.Net Core 3.1.6 ThreadLocal / ThreadStatic.Net Core 3.1.6 ThreadLocal / ThreadStatic
【发布时间】:2020-11-10 09:42:02
【问题描述】:

关于 C# 中的 ThreadStaticThreadLocal 的快速问题,特别是 .Net Core 3.1.6..

我宁愿不发布确切的示例,但它与此非常相似:

[ThreadStatic]
static readonly Object LocalObject = new Object();

然后,我使用 ParrallelEnumerableTasks.Parallel 从多个不同的线程访问所述对象,然后我遇到了一个非常有趣的异常,不幸的是它使运行时崩溃了......

我的代码的意图是每个访问LocalObjectThread 都将拥有自己的实例shown

.Net Core 3.1.6 中的 ThreadLocal / ThreadStatic 是否存在任何已知问题?我可以在哪里了解这些问题?

如果 3.1.6 没有任何变化或不同之处,那么 5.0 中是否存在与相同属性相关的变化?如果这些都没有,那么 .Net 核心从它们的完整框架实现中改变了这些构造的行为?

感谢您的宝贵时间!

【问题讨论】:

  • 错误很可能与您的代码有关,而不是运行时
  • @Jay [ThreadStatic] 不应该这样初始化,因为这意味着,它只对当前线程进行初始化,不会为每个线程初始化,所以在不同的线程中,你必须检查如果它为空并再次初始化它。该库的某个地方的实现者忘记正确初始化它。
  • 使用 ThreadLocal 完全消除了 ThreadStatic 分配问题。两种方法的“问题”真的相同吗?相应地修改标题。我还建议删除“begging the bug”并使用更相关的关于观察到的行为的摘要。

标签: c# thread-local-storage threadstatic


【解决方案1】:

根据您在链接中提供的文档,问题是当您访问变量时,该值为 null 因为:

需要注意的一点是,如果我们初始化 ThreadStatic 变量,例如,如果我们编写以下代码

[ThreadStatic]
static int value = 10;

您需要注意,这仅在声明它的线程上初始化,所有使用 value 的线程都会获得一个使用其默认值初始化的变量,即 0。

因此,如果您尝试对变量执行某些操作,并期望变量具有 Object 实例,它将引发异常,如果不处理该异常将使应用程序失败。

编辑 - 2020 年 7 月 21 日

经过一番测试,我终于得出结论:由于初始化问题,该字段不能为readonly,即该字段只会在第一个线程,内联或static构造函数中初始化。任何后续的thread 只会获得null 值。

我能得到的最接近的如下:

public static void Main(string[] args)
{

    var tsk1 = Task.Run(() => {
       new Test().Display();
    });
    var tsk2 = Task.Run(() => {
       new Test().Display();
    });
    Task.WaitAll(new Task[] { tsk1, tsk2 });
}

class Test {
   [ThreadStatic]
   static Object _localObject;

   // Creates a new instance per thread.
   static Object LocalObject => _localObject ?? (_localObject = new Object());

   public void Display() {
      Console.WriteLine(LocalObject.GetHashCode());
   } 
}

// Sample output:
// C:\Test> dotnet run
// 4032828
// 6044116

【讨论】:

  • stackoverflow.com/questions/5227676/… 这篇文章表明每个线程都有自己的副本......虽然它不是.net核心......你能进一步解释一下吗?
  • 你是说除了静态之外我还需要一个本地,并且当静态为空时,每个本地都需要根据需要进行实例化?我可以试试……你能告诉我这是否是完全 fx 的行为变化吗?谢谢
  • 我更新了我的答案。遗憾的是,正如我在更新中解释的那样,我发现无法使其与字段 static readonly 一起使用。
  • (对于只读的 ThreadStatic,在 any C# 版本或 .NET 实现中,它永远没有意义。人们可以使用 ThreadLocals,甚至直接 TLS,或其中之一获得只读更新的异步感知表单。)
【解决方案2】:
[ThreadStatic]
static Object LocalObject;

And

不要为标有 ThreadStaticAttribute 的字段指定初始值,因为这种初始化只发生一次,当类构造函数执行时,因此只影响一个线程。如果不指定初始值,如果是值类型,则可以依赖被初始化的字段为其默认值,如果是引用类型,则可以依赖为 null。

所以我们删除了readonly 并在每次访问时检查 null 并存储到每个线程上的静态。 (静态构造函数仍然只运行一次)

另请参阅AsyncLocal<T>,尤其是在使用 ThreadPool 线程时,以及Disposing thread static variable

【讨论】:

  • 仍然在问你如何使用static readonly...
  • 没有。对于只读的 ThreadStatic,它通常没有意义。这个答案和引用的摘录解释了原因。我想,可能会有一个边缘案例来识别发生类初始化的线程。[ThreadStatic] private readonly initThread = true.. 虽然我从未在实际代码中看到过。
猜你喜欢
  • 2016-08-28
  • 2013-08-22
  • 2016-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-30
  • 1970-01-01
相关资源
最近更新 更多