c# - .NET 中对象的锁定层次结构

标签 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 接口(interface),该接口(interface)提供 Lock() 方法,该方法将在所有较低级别上(递归地)调用 Lock(),这可能容易出现死锁(循环引用)或成本太高。

我认为设计变更是适当的。

最佳答案

您不需要递归锁定 - 如果两个线程仅锁定同一个 IWorld 引用,则足以确保相互排他性。

锁定各个元素当然会给您提供更细粒度的锁定,但最终可能会得到不一致的图片 - 我想象您希望看到一整套更改一次从服务器。

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

关于c# - .NET 中对象的锁定层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1592818/

相关文章:

c# - OpenPop.net 获取实际消息文本

c++ - 哪个先执行,RAII还是函数返回值

android - Espresso 测试被后台线程阻塞。应用程序未空闲异常 : "AppNotIdleException."

python - 可以在 NFS 文件系统上锁定 sqlite 文件吗?

mysql - 锁(S、X、IS、IX)如何在 Mysql 中使用 FOR UPDATE/LOCK IN SHARE MODE 之类的查询工作?

c# - 如何创建序列号生成器?

c# - asp.net如何获取上个月的日期

javascript - MVC knockout 选择标签值赋值

c# - 如何在多线程环境中只执行一次代码块?

java - 如果可以通过任何其他方法访问对象,那么在同步块(synchronized block)中锁定对象有什么用呢?