当我想知道这个问题时,我担心我正在设计的应用程序中的竞争条件。
假设我有一个由程序的一个组件管理的大型数组或某种集合,我们称该组件为 Monitor。它的工作是定期检查集合是否“脏”,即最近发生了变化,如果是,则将快照写入磁盘(这是在应用程序发生崩溃时检查点)并再次将其标记为干净。
同一程序的其他组件,在不同的线程中运行,调用监视器的方法来添加数据或修改数组/集合中的数据。这些方法将集合标记为脏。
现在,更改方法在其他组件的线程中运行,对吗?如果我不是那么幸运,可能会在将快照写入磁盘时调用它们,更改已写入的数据,设置脏标志,然后监视器的线程将其取消设置,而无需保存更改(它当它改变时已经超过了元素)。所以我有一个被标记为干净的脏集合。
有一段时间,我想我可以通过制作一个临时的集合副本来解决这个问题,把它标记为干净,然后去序列化这个副本。但是复制会是原子的吗,即我可以确定在我复制时集合不会改变吗?
同时,我想我找到了更好的解决方案,比如
- 在开始写入磁盘之前设置锁定标志,并使数据更改方法等到取消设置标志
- 让数据更改方法写入“更改队列”而不是直接写入集合,并让线程执行该队列的磁盘写入过程
我认为锁定标志可能是最好的方法。但我还是很好奇:复制变量是原子的吗?
追问:也许这应该是一个问题,但实际上它非常相似。根据下面的答案,我的“锁定标志”方法也可能不起作用,对吧?因为数据更改方法可能会在锁定标志设置为“锁定”值时检查锁定标志并确定它没有被锁定。因此,如果我真的想正确地做到这一点,我需要一个像互斥锁这样的特殊结构,对吗?