在.NET中锁定对象的层次结构

时间:2009-10-20 06:35:12

标签: c# multithreading locking hierarchy

我有一个代表“世界状况”的课程。该类具有许多其他对象的集合,这些对象又引用了更多对象和对象集合,有时甚至引用了“世界层次结构”中的祖先。为了简化所说的内容,这里有一个例子(转换成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(),这可能会导致死锁(循环引用)或者过于昂贵。

我想设计变更是有序的。

2 个答案:

答案 0 :(得分:3)

您不需要递归锁定 - 如果两个线程只锁定相同的IWorld引用,那么这将足以确保相互排他性。

锁定单个元素当然会给你更细粒度的锁定,但是你最终会得到一张不一致的图片 - 我想想象你想看到一整套变化从服务器一次。

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

答案 1 :(得分:1)

主要问题是如何访问世界各地的元素。 如果通过“世界单身人士”访问所有内容,那么全局锁定就可以了 如果您直接访问国家,城市等,那么如果您需要同时更改链的多个部分,则需要按照完全相同的顺序请求单独的锁。