通过更改集合进行线程化和迭代

时间:2010-06-10 05:30:51

标签: multithreading collections

在C#(控制台应用程序)中,我想要保存一组对象。所有对象都是相同类型的。 我想遍历集合,在每个对象上调用一个方法。然后不断重复这个过程。 但是,在迭代期间,可以在列表中添加或删除对象。 (对象本身不会被销毁..只是从列表中删除)。 不确定foreach循环或其他类似方法会发生什么。 这之前必须完成1000次..你能推荐一个可靠的方法吗?

3 个答案:

答案 0 :(得分:1)

还有基于副本的方法。 算法是这样的:

  1. 锁定共享馆藏
  2. 将所有项目从共享集合复制到某个本地集合
  3. 释放对共享集合的锁定
  4. 迭代本地收藏中的项目
  5. 这种方法的优点是你可以在很短的时间内锁定共享集合(假设共享集合相对较小)。

    如果要在每个集合项上调用的方法需要相当长的时间才能完成或者可以阻塞,那么在共享锁下进行迭代的方法可能会导致阻塞其他想要添加/删除共享集合中的项的线程< / p>

    但是,如果要在每个对象上调用的方法相对较快,那么在共享锁下进行迭代可能更为可取。

答案 1 :(得分:0)

这是多线程中同步的经典案例。

只有坚实的方法和更好的方法才能在循环和添加/删除列表中的项目之间实现同步。

意味着你应该只允许在结尾和迭代循环开始时添加/删除!

这样的事情: -

    ENTER SYNC_BLOCK
      WAIT FOR SYNC_BLOCK to be available

      LOOP for items/ call method on them.

     LEAVE SYNC_BLOCK


     ENTER SYNC_BLOCK
      WAIT FOR SYNC_BLOCK to be available

     Add/Delete items

 LEAVE SYNC_BLOCK

答案 2 :(得分:0)

我在阅读此示例时想到的是,您可以使用C5 TreeSet / TreeBag。它确实需要有一种订购商品的方式,但Tree收藏品的优势在于它们提供Snapshot方法(C5.IPersistentSorted成员),可让您制作集合状态的轻量级快照,无需完全复制。

e.g:

using(var copy = mySet.Snapshot()) {
  foreach(var item in copy) {
    item.DoSomething();
  }
}

C5还提供了一种“适用于所有人”的简单方法,并且与.NET 2.0兼容:

using(var copy = mySet.Snapshot()) {
  copy.Apply(i => i.DoSomething());
}

重要的是要注意快照应该被丢弃,否则您将对后续修改基本集合产生很小的性能损失。

此示例来自非常彻底的C5 Book