List.AddRange() 线程安全吗?

发布于 2024-09-29 18:14:03 字数 67 浏览 1 评论 0原文

我可以在不锁定的情况下从多个线程安全地调用 List.AddRange(r) 吗?如果不是的话,我会遇到什么样的麻烦呢?

Can I, without locking, safely call List.AddRange(r) from multiple threads? If not, what sort of trouble would I run into?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

放低过去 2024-10-06 18:14:03

其文档没有说明它是线程安全的,因此它不是。

公共静态(在 Visual Basic 中共享)
该类型的成员是线程安全的。
任何实例成员都不是
保证线程安全。

至于会出现什么问题,想一下 AddRange(newItems) 的作用:

  • 检查内部数组是否有足够的空间
  • 如果没有:
    • 分配一个新数组
    • 将当前项复制到新数组
    • 设置一个字段以指向新数组
  • 将 newItems 复制到内部数组中正确的本地位置
  • 更新“count”字段(这用于控制 现在想想,如果上述内容

与对 AddRange() 的另一个调用混合在一起,甚至只是与读取一个项目的调用混合在一起,会发生什么。

No, its documentation does not say it is thread safe, therefore it is not.

Public static (Shared in Visual Basic)
members of this type are thread safe.
Any instance members are not
guaranteed to be thread safe.

As to what can go wrong, think about what AddRange(newItems) does:

  • Check if there is enough space in the internal array
  • If not:
    • Allocate a new array
    • Copy the current items to the new array
    • Set a field to point at the new array
  • Copy the newItems to the correct local in the internal array
  • Update the “count” field (this is used to control where the next item is inserted)

Now think what will happen if the above is mixed up with another call to AddRange() or even just a call to read an item.

扭转时空 2024-10-06 18:14:03

不,不是,但我想补充一点,在锁内执行 myList.AddRange(...); 比执行多个 lock (syncLock) { myList.Add 更有效(...) };

你会遇到什么样的麻烦?当一个线程添加一项而另一个线程枚举列表时,List 将抛出特定异常,因为它会进行一些内部版本控制,因为它希望防止我们可怜的开发人员遇到令人讨厌的副作用。

此外,List 在内部保留一个用于存储其项目的数组。也许在数组中设置一项是非常原子的,但是每当达到该数组的容量时,就会创建一个新数组,并且将从旧数组中复制这些项。因此,当线程想要在复制发生时添加某些内容时,您可以想象事情会不同步。

No it's not, but I'd like to add it's more efficient to do an myList.AddRange(...); within a lock than doing several lock (syncLock) { myList.Add(...) };.

Which sort of trouble would you run into? When one thread is adding an item while another is enumerating the list, List<T> will throw a certain exception because it does some internal versioning, as it wants to prevent us poor developers from hitting nasty side effects.

Also the List<T> internally keeps an array in which it stores its items. Maybe setting an item in an array is pretty atomic, but whenever the capacity of this array is reached, a new one will be created and the items will be copied over from the old one. So when a thread wants to add something while that copying takes place, you can imagine that things would go out of sync.

岁月流歌 2024-10-06 18:14:03

根据您的使用情况,SynchronizedCollection 可能会起作用。

不过,您没有单次 AddRange 。如果您仅使用它来为集合播种,则可以执行此操作,因为存在 IEnumerable 构造函数重载。

Depending on your usage, SynchronizedCollection could work.

You'd have no single-shot AddRange though. If you are only using this to seed the collection, you can do this as there is an IEnumerable constructor overload.

嗳卜坏 2024-10-06 18:14:03

在 .NET Framework 4.0 之前,没有 .NET 集合是线程安全的。然后,您需要先锁定它,然后才能在代码中访问它 集合和同步(线程安全)

另一方面,.NET Framework 4.0 引入了新的 System.Collections.Concurrent 命名空间,其中包括细粒度 线程安全集合

最后,如果您可以使用.NET Framework 4.0,我强烈建议您根据需要这样做,否则,请确保每次要修改或访问集合时都锁定该集合。

此外,静态集合应该是线程安全的,但要小心,因为不能保证成员是线程安全的。

编辑 #1

经过 Steve Townsend 评论的进一步验证,我承认从版本 3.0 开始,.NET Framework 中存在三个线程安全集合

  1. : microsoft.com/en-us/library/ms668265%28v=VS.85%29.aspx" rel="nofollow">SynchronizedCollection 通用类;
  2. SynchronizedKeyedCollection 通用类
  3. SynchronizedReadOnlyCollection 通用类

我很抱歉,我自己才知道他们的存在。 =)

Until .NET Framework 4.0, no .NET collections are thread-safe. You will then be required to lock it before you access it in your code Collections and Synchronization (Thread Safety).

On the other hand, .NET Framework 4.0 introduces the new System.Collections.Concurrent namespace which includes fine-grained Thread-Safe Collections.

Finally, if you can use .NET Framework 4.0, I strongly recommend you do so for what you need, otherwise, make sure to lock the collection each time you want to modify or access it.

Besides, a static collection should be thread-safe, but beware, as the members are not guaranteed to be.

EDIT #1

After further verifications due to Steve Townsend's comment, I admit that there are three thread-safe collections within the .NET Framework starting with version 3.0:

  1. SynchronizedCollection Generic Class;
  2. SynchronizedKeyedCollection Generic Class;
  3. SynchronizedReadOnlyCollection Generic Class.

I apologize, I just learned their exitense myself. =)

别再吹冷风 2024-10-06 18:14:03

不,它不是线程安全的。

线程 A 可以调用您的列表上的 AddRange。它可以部分地迭代集合并切换线程。

线程 B 可以在线程 A 完成之前调用添加/删除等。

No it is not thread-safe.

Thread A could call AddRange on your list. It could iterate partially over the collection and switch threads.

Thread B could call Add/Remove, etc. before Thread A has finished.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文