Объект изменен другим потоком - PullRequest
1 голос
/ 30 мая 2011

Эта проблема встречается в части сложной системы, где многим потокам необходим доступ к одному и тому же методу. Этот проект написан на 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 ]

2 голосов
/ 30 мая 2011

вы говорите food - это string; теперь string s являются неизменяемыми, поэтому , что не изменилось во время метода - и параметр food не является опорным (ref), поэтому , что не изменился во время метода.

Converter.XMLStringToObject появляется (сложно сказать), чтобы проанализировать строку для объекта, поэтому там нет общего состояния, если у вас нет кеша, о котором вы нам не сказали.

Итак ... это просто ошибка в вашем коде; не имеет ничего общего с потоками.

Примечание: параметры метода и переменные на вызов - они изолированы (если они не относятся к общему состоянию).

Это не проблема с потоками. Просто заурядная ошибка. В какой-то момент во время разбора вы назвали его яблоком, но присвоили ему оранжевый. Проследите через XMLStringToObject, чтобы найти его, в частности, посмотрите, где назначены .FoodType и FoodObject.

В качестве отступления - lock(this) - плохая идея в общем ; в этом случае он также не делает ничего полезного, поскольку у вас нет общего состояния для защиты. Если бы было использованием, было бы предпочтительным иметь выделенный объект для этого:

private readonly object syncLock = new object();
...
lock(syncLock) {...}
0 голосов
/ 30 мая 2011

Как предложил Марк Гравелл, использовать отдельный экземпляр Object для блокировки и избавления от исключения

Apple apple = foodObj.FoodObject as Apple;

if(apple != null)
{
 // do something here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...