Object changed by another thread
This problem is en开发者_开发技巧countered in part of a complicated system where many threads need to access to the same method. This project is written in C#. To simplify the problem, I use the following illustration:
I have two customised classes, the parent class of these two classes is the same. The two classes are Apple and Orange, the parent is Fruit. The problem came when I expect an apple, but it is actually an Orange. This happens sometimes, not not a rare event, probably 10% of the time.
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
...
}
...
}
}
The InvaildCastException says I am trying to cast an Orange to an Apple, when I have already handled it by "lock(this)" and the if checking. Have I handled it incorrectly? How should I resolve this issue?
you say food
is a string
; now, string
s are immutable, so that hasn't changed during the method - and the parameter food
is not by-ref (ref
), so that hasn't changed during the method.
Converter.XMLStringToObject
appears (hard to say) to parse the string to an object, so there is no shared state there unless you have some cache that you haven't told us about.
So... this is just a parsing bug in your code; nothing to do with threading.
Note: method parameters and variables are per call - they are isolated (unless they refer to shared state).
This is not a threading issue. Just a run-of-the-mill bug. At some point during parsing, you've called it an apple, but assigned it an orange. Trace through XMLStringToObject
to find it, looking in particular at where .FoodType
and FoodObject
get assigned.
As an aside - lock(this)
is a bad idea in general; in this case, it also does nothing useful since you have no shared state to protect. If there was a use, having a dedicated object for this would be preferred:
private readonly object syncLock = new object();
...
lock(syncLock) {...}
As Marc Gravell suggested use a separate Object instance for lock purpose and to get rid of the exception
Apple apple = foodObj.FoodObject as Apple;
if(apple != null)
{
// do something here
}
精彩评论