2

我有一个代表“世界状态”的课程。该类有许多其他对象的集合,这些对象又引用更多对象和对象集合,有时甚至引用它们在“世界层次结构”中的祖先。为了简化所说的,这里有一个例子(转换成 XML,细节省略):

<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线程和后台线程(实际上是一个服务器)。

服务器接收修改“世界状态”(添加城市、街区等)的消息。

UI 线程每隔一段时间使用 PictureBox 对象将世界的状态绘制到屏幕上。表示层仅引用 IWorld 对象(World 实现),它无法访问其中的元素。

UI 线程应该锁定世界的完整状态,以便在绘制期间不能(通过服务器)更改世界(这会产生不一致的世界图片)。因为它只引用了 IWorld 对象,所以这是唯一要锁定的东西。

我的问题是这个锁是否足够(即,递归地锁定该对象具有的所有字段和属性),或者每个对象都应该单独锁定。解决这个问题的正确方法是什么?

注意: UI 无法联系服务器(意味着它不能告诉服务器停止改变世界,然后在渲染后告诉它恢复)。

编辑:如果 World 和层次结构中的所有类都实现 ILock 接口,该接口提供 Lock() 方法,该方法将在所有较低级别(递归地)调用 Lock(),这可能容易出现死锁(循环引用)或太昂贵。

我想设计更改是有序的。

4

2 回答 2

2

您不需要递归锁定 - 如果两个线程都锁定在同一个IWorld引用上,这足以确保互斥性。

锁定单个元素当然会给你更细粒度的锁定,但是你最终可能会得到一个不一致的图片 - 我想会希望一次看到来自服务器的一整套更改。

但是,更好的模型通常是让服务器发布“快照”,然后创建世界的新副本并修改副本,在适当的时候将其转换为快照。这样你就不需要这种互斥,当它想要在服务器改变它的时候绘制世界时,它可能会阻塞你的 UI。

于 2009-10-20T06:41:03.673 回答
1

主要问题是如何访问世界下方的元素。如果一切都是通过“世界单例”访问的,那么全局锁就很好而且安全。
如果您直接访问国家、城市等...,那么您需要单独的锁,如果您需要同时更改链的多个部分,则需要以完全相同的顺序请求这些锁。

于 2009-10-20T06:40:01.840 回答