为什么这个对象是空的

本文关键字:对象 为什么 | 更新日期: 2023-09-27 18:15:02

我有一个静态字段的类,像这样

public class MyClass
{
    public static Guid MyField1 { get; set; }
}

那么我有一个这样的方法。

public void MyMethod()
{
   MyClass.MyField1  = Guid.NewID();
   Task.Factory.StartNew( () =>  { MyAnotherMethod(MyClass.MyField1);}) ;
}

问题是,当我点击调用缅甸方法(),我得到一个异常,'MyClass. 'MyField1'抛出了类型为'System.NullReferenceException'的异常。然而,如果我用下面替换Task.Factory.StartNew调用,它工作得很好。

ThreadPool.QueueUserWorkItem(MyAnotherMethod, MyClass.MyField1);

任何想法?

为什么这个对象是空的

我认为这是一个线程/缓存问题。在线程1中,您将11赋值给属性,但该值在缓存中,线程2不知道(例如,它正在查看RAM)。为了避免这个问题,你可以使用锁,或者在变量上指定volatile关键字。

试试这个:

private static volatile int myField1;
public static int MyField1 { get { return myField1; } set { myField1 = value; } }

并行调用方法的两个版本之间存在差异。在Task版本中,将Task代码定义为不带参数的lambda函数,并在其中执行代码

MyAnotherMethod(MyClass.MyField1);

在ThreadPool版本中,您将传递给ThreadPool的任务定义为要用初始参数MyClass.MyField1启动的方法MyAnotherMethod的代码。

如果在调用ThreadPool.QueueUserWorkItem之后,您以某种方式修改了MyField1,则任务启动将不会受到任何影响,因为MyField1已经在堆栈上复制并且任务开始执行。

另一方面,如果在调用StartNew之后修改MyField1,则可能在Task方法内部的方法调用发生之前发生数据争用,并且Task内部的方法以不同的MyField1值执行。