对象由另一个线程更改

时间:2011-05-30 07:19:28

标签: c# visual-studio multithreading thread-safety

在许多线程需要访问同一方法的复杂系统的一部分中遇到此问题。这个项目是用C#编写的。为简化问题,我使用下图:

我有两个自定义类,这两个类的父类是相同的。这两个类是Apple和Orange,父母是Fruit。当我期待一个苹果时出现问题,但它实际上是一个橘子。 这种情况有时发生,并非罕见事件,可能是10%的时间。

public void MethodAlpha(object food)
{
   lock(this)
   {
       FoodObj foodObj = Converter.XMLStringToObject(food, ...) //"food" is a string

       if(foodObj.FoodType == StringConstants.Apple)
       {
           Apple apple = (Apple)foodObj.FoodObject; <--InvaildCastException
           ...
       }
       ...
   }
}

InvaildCastException说我正在尝试将Orange转换为Apple,当我已经通过“lock(this)”和if检查来处理它时。我是否错误地处理了它?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

你说foodstring;现在,string是不可变的,所以 在方法期间没有改变 - 参数food不是by-ref(ref),所以 在此方法期间未发生变化。

Converter.XMLStringToObject 出现(很难说)将字符串解析为一个对象,因此除非你有一些你没有告诉我们的缓存,否则就没有共享状态。

所以......这只是代码中的一个解析错误;与线程无关。

注意:方法参数和变量每次调用 - 它们是隔离的(除非它们引用共享状态)。

这不是线程问题。只是一个普通的错误。在解析期间的某个时刻,你已经称为苹果,但为其分配了橙色。追踪XMLStringToObject以找到它,特别关注.FoodTypeFoodObject被分配的位置。

顺便说一下 - lock(this)一般来说是个坏主意;在这种情况下,它也没有任何用处,因为你没有要保护的共享状态。如果一个用途,那么首选拥有一个专用对象:

private readonly object syncLock = new object();
...
lock(syncLock) {...}

答案 1 :(得分:0)

正如Marc Gravell建议使用一个单独的Object实例来锁定目的并摆脱异常

Apple apple = foodObj.FoodObject as Apple;

if(apple != null)
{
 // do something here
}