添加到列表(或堆栈或队列)但不读取列表时的争用条件<T> - 会发生什么?



注意:我问这个问题是关于3.5框架的,所以我没有包括4.0中任何较新的多线程结构(我仍在学习)。

我一直在努力想出一个答案,试图结束我一直在争论的问题,但我觉得我没有找到一个结论性的描述,关于在接下来的场景中会发生什么。

假设你有一个应用程序,它有多个线程,每个线程都在生成对象,每个线程生成一个唯一的对象。集合(List、Stack或Queue)的单个实例是对象创建后的存储库,对象一旦添加到集合中,实际上是不可变的。

在此过程中,对集合的唯一操作是添加项。不需要读取、删除或计数。集合中项的顺序无关。

问题是,如果当各个线程试图添加对象时,集合周围没有锁定,这真的是一个问题吗?

我说是的,但是几乎所有关于竞态条件为什么有问题的教科书描述都是一端是读,另一端是竞态,或者是对单个变量进行写入,所以我没有足够的证据来有效地论证我的观点。

我说是的原因基本上归结为这样一个事实:集合不是被设计为线程安全的,所以你可能会遇到意想不到的或未定义的行为,即使只执行"写"。我猜想存在这样一种风险:两个线程可能会尝试将它们的对象添加到集合中的同一个槽中,因此,当对象被覆盖时,您会丢失对象,但我没有发现任何表明这确实是可能的。或者可能存在一些幕后问题,例如当集合需要自身增长以容纳更多项时。

谁能给我提供一些信息来平息这场争论?我特别想知道是否有什么能证明我错了。

List<T>(或堆栈等)添加项不是线程安全的

这涉及到

  • 检查内部数组大小是否足够
  • 如果没有,创建一个新的数组,复制所有项目
  • 在数组中设置索引等于List<T>
  • 长度的项

以上进程都不是线程安全的并且在。net框架代码中没有同步。因此,如果您不同步,我保证您的列表将被损坏。

向列表中添加项涉及到内存的读写,因此除非存在同步,否则存在竞争。

你基本上是对的,尽管一些更简单的结构,如堆栈或队列可能"意外地"是线程安全的。您无法保证任何集合的"内部"是如何实现的。例如,列表由数组支持。如果添加新项导致数组增长,它将(可能)将所有值复制到一个新的更大的数组中。在其实现中可能是线程安全的,但由于它不是一个线程安全对象,因此它的线程安全没有契约。

最新更新