为什么这个对象是null?

时间:2011-11-18 15:24:54

标签: c# multithreading .net-4.0 task-parallel-library task

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

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

然后我有这样的方法。

public void MyMethod()
{

   MyClass.MyField1  = Guid.NewID();

   Task.Factory.StartNew( () =>  { MyAnotherMethod(MyClass.MyField1);}) ;
}

问题是当我点击对MyAnotherMethod()的调用时,我得到一个异常,'MyClass.MyField1'抛出了类型'System.NullReferenceException'的异常。但是,如果我用下面替换Task.Factory.StartNew调用,它可以正常工作。

ThreadPool.QueueUserWorkItem(MyAnotherMethod, MyClass.MyField1);

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我认为这是一个线程/缓存问题。在线程1中,为属性分配11,但值在缓存中,而线程2不知道(例如,它正在查看RAM)。要避免此问题,您可以使用锁定,也可以在变量上指定volatile keyword

试试这个:

private static volatile int myField1;

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

答案 1 :(得分:0)

并行调用该方法的两个版本之间存在差异。在任务版本中,您将任务代码定义为没有参数的lambda函数,并在内部执行代码

MyAnotherMethod(MyClass.MyField1);

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

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

另一方面,如果在调用StartNew之后修改MyField1,则可能在Task方法内部的方法调用发生之前发生数据争用,并且Task内部的方法执行时MyField1的不同值。我希望你能理解我在这里想说的话......