【问题标题】:Is it thread-safe to replace a concurrent collection when there may be iterators?当可能存在迭代器时,替换并发集合是否是线程安全的?
【发布时间】:2015-02-05 01:20:00
【问题描述】:

我一直在阅读各种内容,看起来这应该可行,但我想确定一下。我有一个静态属性,它应该是一个缓存(加上一些与缓存数据相关的其他功能)。它将实际数据存储在 ConcurrentBag 中,并且它有一个 IEnumerable 方法来[过滤并] 从这个包中产生返回值。它会像这样更新自己:

ConcurrentBag<Foo> NewBag = GetNewThings();
Cache = NewBag;

从我读到的内容来看,这似乎应该可行,尽管我没想到它会这样。我希望这会在发生这种情况时炸毁正在读取的任何迭代器。但是我读到如果另一个线程正在遍历旧列表,它将在列表的该实例上完成,而新列表被交换。第二个(新)线程将在新列表上启动,即使旧线程仍在迭代它们的旧实例。不过这看起来很神奇,所以我可能错了,是吗?

其他线程只迭代列表,唯一的写入发生在这两行。

【问题讨论】:

  • 请注意,只有一小部分“魔术”与线程相关(事实上,指针大小的赋值是原子的),其余的行为可以很容易地在单线程同步代码中看到 - 改变值保存集合的变量对集合本身及其迭代器没有影响。
  • 线程安全不是传递属性。您不能通过迭代来破坏 ConcurrentBag 的事实确实not 意味着您的 代码是线程安全的。很少有,处理不再在包中的对象或在开始迭代后没有看到任何添加的对象很少会得到很好的结果。

标签: c# multithreading


【解决方案1】:

我读到如果另一个线程正在遍历旧列表,它 将在新列表获取时在列表的该实例上完成 交换了。第二个(新)线程将在新列表上启动,即使在 旧线程仍在迭代它们的旧实例。这个 不过看起来很神奇,所以我可能错了,是吗?

你读的是正确的。

这是线程安全的,但您可能希望创建变量 volatile 或使用 Volatile.ReadVolatile.Write 以确保所有线程的即时可见性。

【讨论】:

  • 这回答了我遇到的另一个问题:易失性,我也对此进行了研究。谢谢!
【解决方案2】:

分配给Cache 的原始实例仍然存在,这是旧线程正在迭代的那个。

新线程对GetNewThings()结果进行操作。

【讨论】:

    猜你喜欢
    • 2011-05-29
    • 2021-07-10
    • 2016-01-16
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    相关资源
    最近更新 更多