简短的回答是InterlockedExchange 不太可能帮助您。但重要的是要了解为什么会出现这种情况,这样您才能更好地了解可能有帮助的情况。
为什么并发读写有问题?
首先请注意,任意数量的线程都可以读取相同的数据,而无需担心。我们只有在一个线程能够并发写入时才开始担心。现在,写作本身并没有什么固有的风险。当即使是最轻微的决策逻辑应用于并发使用的共享数据时,问题也会出现。
例如,您可能有一个列表。一个线程(作者)从列表中删除一个元素,而其他线程正在读取列表中的元素。如果您对操作的时间不满意,读者可能会在作者删除它的同时确认一个元素存在。然后,当阅读器尝试使用 不再有效 元素时,充其量是访问冲突,最坏的情况是数据损坏。
如何保护数据
保护数据的最简单方法(无需架构更改)通常是引入一些表单锁定/阻塞机制。在一个线程开始一项关键操作之前,它会说:“我正忙于共享数据,所有其他线程必须等待直到我完成才能使用数据。”
请注意,这种简单化的方法确实会带来其他问题:
- 如果许多线程将大部分时间都花在等待或“争夺锁”上,性能可能会显着降低。
- 锁管理问题会导致两个线程相互阻塞,从而导致系统挂起(称为死锁)。
(注意:有许多替代方法可以保护您的数据,但这超出了本文的范围。)
互锁交换
这个例程和它的其他Interlocked*** 兄弟提供了一个简化的锁定机制,覆盖了基本的、通用的 写操作的步骤。 注意 如上所述,它仍然是一种锁定机制,并且存在大部分问题。
InterlockedExchange保护的两步操作是:
这个可能需要保护的原因是,如果两个线程同时交换一个共享值,就有可能出现不一致的行为。
例如给定初始值为 A。线程 #1 交换将值设置为 B。线程 #2 交换将值设置为 C。如果线程同时运行与 #1 处理的时间比 #2 稍早,则有 2 种可能的结果。
- 使用锁定 #2 将被阻塞,直到 #1 完成,最终结果将始终为:值设置为 C。线程 #1 引用了 A。线程 #2 引用了 B。
- 如果没有锁定,我们通常会得到与上面相同的结果,但也有我们没有的可能性。最终结果可能是:值设置为 C。线程 #1 引用了 A。线程 #2 引用了
A <-- Discrepancy。
这并不总是一个问题,但在某些情况下可能会。在这种情况下,InterlockedExchange 是最简单的基于锁的保护机制。
为什么 InterlockedExchange 不太适合您
您说您的数据在列表中,但没有说明是哪种列表;所以我假设一个标准的德尔福TList。将项目插入列表中并不是一个简单内部操作。
- 会自动维护一个内部计数器。
- 可能需要移动现有项目。
- 需要检查列表的当前容量,并且可能需要增加。
注意!注意:即使您使用的列表数据结构本身可以从InterlockedExchange 中受益,还有其他问题 你需要注意。
您在这里有两组组数据。有列表结构的内部数据(你可能不这么认为,但它就在那里)。然后是您的实际记录数据。
即使在保护了您的列表结构之后,如果您有任何线程可以同时更新您的记录,那么您就有一个潜在的问题。您需要保护您的数据 - 而不仅仅是将数据添加到集合中。这意味着您可能需要一个跨越两个数据集的锁定机制;并且任何基本的、通用的Interlocked*** 例程都不可能实现这一点。