2009-10-20 3 views
2

У меня есть класс, который представляет «состояние мира». Класс имеет много коллекций многих других объектов, которые, в свою очередь, имеют ссылки на большее количество объектов и коллекций объектов, иногда даже ссылок на своих предков в «мировой иерархии». Для того, чтобы упростить то, что, как говорится, вот пример (преобразуется в XML, детали опущены):Блокировка иерархии объектов в .NET

<World> 
<Country> 
    <City> 
     <Block> 
     ... 
     </Block> 
    </City> 
    <City> 
     <Block> 
     ... 
     </Block> 
    </City> 
</Country> 
... 
<Country> 
    <City> 
     <Block> ... </Block> 
     ... 
     <Block> ... </Block> 
    </City> 
    <City> 
     <Block> ... </Block> 
    </City> 
</Country> 
</World> 

Есть два потока, поток UI и фоновый поток (который на самом деле сервер).

Сервер получает сообщения, которые изменяют «состояние мира» (добавление городов, блоков и т. Д.).

Нить пользовательского интерфейса рисует состояние мира, чтобы отображать с помощью объекта PictureBox раз в то время. Уровень представления содержит только ссылку на объект IWorld (который реализует World), и он не имеет доступа к элементам внутри.

Нить UI должна зафиксировать полностью состояние мира, так что мир не может быть изменен (сервером) во время рисования (что сделало бы несогласованную картину мира). Поскольку он имеет только ссылку на объект IWorld, это единственное, что нужно заблокировать.

Мой вопрос заключается в том, достаточно ли этой блокировки (т. Е. Блокировать все поля и свойства, которые этот объект имеет, рекурсивно), или каждый объект должен блокироваться отдельно. Каков правильный подход к этой проблеме?

Примечание: Пользовательский интерфейс не имеет возможности связаться с сервером (это означает, что он не может сказать серверу прекратить изменять мир, а затем сказать ему возобновить после рендеринга).

EDIT: Если мир и все классы в иерархию реализации интерфейса ILock, который обеспечивает блокировку() метод, который бы назвал блокировку() на всех нижних уровнях (рекурсивно), то это, вероятно, будет склонен к тупиковой ситуации (циклические ссылки) или просто слишком дорого.

Я думаю, что изменение конструкции в порядке.

ответ

3

Вам не нужно блокировать рекурсивно - если оба потока просто блокируются на одном и том же значении IWorld, этого будет достаточно для обеспечения взаимной исключительности.

Блокировка от отдельных элементов даст вам тонкоуровневого запирание конечно, но тогда вы могли бы в конечном итоге с несовместимым картины - я бы себе представить, что вы хотели бы видеть целый ряд изменений с сервера на время.

Однако лучшей моделью обычно было бы заставить сервер публиковать «моментальные снимки», а затем создавать новую копию мира и модифицировать копию, превращая ее в моментальный снимок, когда это необходимо. Таким образом, вам не нужно это взаимное исключение, которое может блокировать ваш пользовательский интерфейс, когда он хочет нарисовать мир, пока сервер его меняет.

+0

Несмотря на то, что это не дает однозначного ответа на вопрос, оно дает хороший смысл в необходимости изменения дизайна (и довольно легко реализовать). Благодарю. –

+0

Я не вижу, как он не отвечает на вопрос: первое предложение отвечает на это, подумал я. Самый простой способ обеспечить взаимное исключение для всего мира - это просто сделать блокировку обоих потоков одной и той же ссылкой. –

+0

В некотором смысле это не так: Очевидно, что если два объекта пытаются заблокировать одну и ту же ссылку, этого достаточно, чтобы обеспечить взаимную эксклюзивность. Но мой вопрос был на самом деле достаточно ли, если один объект блокирует объекты верхнего уровня, а другой объект блокирует объект нижнего уровня. Но теперь, когда я думаю об этом, это было бы бессмысленно. ОС должна была бы заблокировать все ссылки на объекты, и это создало бы тупик при обнаружении первой циклической ссылки. Так что, наверное, мой вопрос не был точно продуман во-первых. –

1

Главный вопрос заключается в том, как вы получаете доступ к элементам под землей. Если все доступно через «Мировой синглтон», тогда глобальная блокировка будет прекрасной и безопасной.
Если вы напрямую обращаетесь к странам, городам и т. Д., Вам нужны отдельные блокировки, которые необходимо запросить в том же порядке, если вам нужно изменить несколько частей цепи в одно и то же время.

+0

Итак, если сервер может получить доступ к объектам мира нижнего уровня через интерфейс IWorldModify, то блокировки только объекта верхнего уровня будет недостаточно? –

+0

Посмотрите на реализацию MS Singleton: http://msdn.microsoft.com/en-us/library/ms998558.aspx Если вы использовали многопоточную реализацию, то вы в порядке. Предложения Джона также актуальны, если вы столкнулись с проблемами производительности. – weismat