【问题标题】:Is it safe to add and remove items from a List object?从 List 对象中添加和删除项目是否安全?
【发布时间】:2020-04-01 07:35:15
【问题描述】:

假设我们有多个线程和一个负责保存实时数据的公共List。我们有一些线程负责将数据添加到列表对象。另一个线程负责从列表对象中获取数据,然后从顶部删除项目。

问题:从List 的开头删除并同时在单独的线程中将数据添加到列表末尾是否安全? List对象是如何实现的?

【问题讨论】:

标签: c# multithreading thread-safety


【解决方案1】:

来自docs

这种类型的公共静态成员是线程安全的。 不保证任何实例成员都是线程安全的。

对 List 执行多次读取操作是安全的,但如果在读取时修改集合,则会出现问题。

因此,如果您的集合可以被某些线程修改 - 您需要在写入读取操作时lock它。

文档还为您指出了另一个解决方案:

对于具有内置同步的集合,请参阅 System.Collections.Concurrent 命名空间中的类。

例如ConcurrentQueue。使用.Enqueue(obj) 将其插入队列末尾,使用TryDequeue(out obj) 将其从队列顶部获取。

【讨论】:

  • 谢谢。 Dequeue 是否完全从 ConcurrentQueue 中移除并减小对象的大小?
  • “所以,如果您在从中删除元素的同时锁定您的收藏 - 就可以了。”这有点误导。访问列表时必须使用锁,而与线程的作用无关。如果您使用读写锁,您可能会更高效,但读取线程仍然需要锁
  • @HOPE,是的,TryDequeue 从队列中删除元素。还有一个TryPeek,它只是从顶部“窥视”一个元素而不删除。
  • @Voo,同意。我改写了这句话以减少误导。
  • 谢谢。 IProducerConsumerCollection 是一个不错的选择。我现在已经用了:)。
【解决方案2】:

列表不是线程安全的。

您要解决的问题看起来像是生产者-消费者问题,所以您需要一个实现IProducerConsumerCollection<T> 的集合:

如果您还需要有界缓冲区(始终只允许集合中的一定数量的项目),您可以使用BlockingCollection<T>,将上述任何一个作为内部集合。

【讨论】:

  • 谢谢。 IProducerConsumerCollection 是一个不错的选择。我现在已经用了 :) .
猜你喜欢
  • 2017-11-30
  • 1970-01-01
  • 2021-07-30
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-06
相关资源
最近更新 更多