在。net 4.0中看到新的System.Collections.Concurrent命名空间,我非常激动,非常棒!我已经看到ConcurrentDictionary, ConcurrentQueue, ConcurrentStack, ConcurrentBag和BlockingCollection。

有一样东西似乎神秘地丢失了,那就是ConcurrentList<T>。我必须自己写吗(或者从网上得到:))?

我是不是遗漏了什么明显的东西?


当前回答

你用ConcurrentList做什么?

在线程世界中,随机访问容器的概念并不像它看起来那样有用。该声明

  if (i < MyConcurrentList.Count)  
      x = MyConcurrentList[i]; 

总的来说仍然不是线程安全的。

与其创建ConcurrentList,不如尝试使用现有的内容构建解决方案。最常见的类是ConcurrentBag,尤其是BlockingCollection。

其他回答

没有ConcurrentList的原因是因为它根本不能被写入。原因是在IList中有几个重要的操作依赖于索引,而这根本行不通。例如:

int catIndex = list.IndexOf("cat");
list.Insert(catIndex, "dog");

作者所追求的效果是在“cat”之前插入“dog”,但在多线程环境中,这两行代码之间的列表可能发生任何事情。例如,另一个线程可能执行list. removeat(0),将整个列表向左移动,但关键的是,catIndex不会改变。这里的影响是Insert操作实际上将“狗”放在猫之后,而不是在它之前。

The several implementations that you see offered as "answers" to this question are well-meaning, but as the above shows, they don't offer reliable results. If you really want list-like semantics in a multithreaded environment, you can't get there by putting locks inside the list implementation methods. You have to ensure that any index you use lives entirely inside the context of the lock. The upshot is that you can use a List in a multithreaded environment with the right locking, but the list itself cannot be made to exist in that world.

如果你认为你需要一个并发列表,实际上只有两种可能:

你真正需要的是一个ConcurrentBag 您需要创建自己的集合,可能使用List和自己的并发控制来实现。

If you have a ConcurrentBag and are in a position where you need to pass it as an IList, then you have a problem, because the method you're calling has specified that they might try to do something like I did above with the cat & dog. In most worlds, what that means is that the method you're calling is simply not built to work in a multi-threaded environment. That means you either refactor it so that it is or, if you can't, you're going to have to handle it very carefully. You you'll almost certainly be required to create your own collection with its own locks, and call the offending method within a lock.

在顺序执行的代码中,使用的数据结构与(编写良好的)并发执行的代码不同。原因是顺序代码隐含着隐式的顺序。然而并发代码并不意味着任何顺序;更妙的是,它暗示着缺乏任何明确的秩序!

因此,具有隐含顺序的数据结构(如List)对于解决并发问题不是很有用。列表意味着顺序,但它并没有清楚地定义这个顺序是什么。因此,操作列表的代码的执行顺序将(在某种程度上)决定列表的隐式顺序,这与有效的并发解决方案直接冲突。

记住,并发是一个数据问题,而不是代码问题!您不能先实现代码(或重写现有的顺序代码),然后获得设计良好的并发解决方案。您需要首先设计数据结构,同时记住在并发系统中不存在隐式排序。

如果不需要处理太多项,无锁复制和写入方法非常有效。 下面是我写的一个类:

public class CopyAndWriteList<T>
{
    public static List<T> Clear(List<T> list)
    {
        var a = new List<T>(list);
        a.Clear();
        return a;
    }

    public static List<T> Add(List<T> list, T item)
    {
        var a = new List<T>(list);
        a.Add(item);
        return a;
    }

    public static List<T> RemoveAt(List<T> list, int index)
    {
        var a = new List<T>(list);
        a.RemoveAt(index);
        return a;
    }

    public static List<T> Remove(List<T> list, T item)
    {
        var a = new List<T>(list);
        a.Remove(item);
        return a;
    }

}

使用示例: orders_BUY = CopyAndWriteList.Clear(orders_BUY);

你用ConcurrentList做什么?

在线程世界中,随机访问容器的概念并不像它看起来那样有用。该声明

  if (i < MyConcurrentList.Count)  
      x = MyConcurrentList[i]; 

总的来说仍然不是线程安全的。

与其创建ConcurrentList,不如尝试使用现有的内容构建解决方案。最常见的类是ConcurrentBag,尤其是BlockingCollection。

ConcurrentList(作为一个可调整大小的数组,而不是一个链表)不容易用非阻塞操作编写。它的API不能很好地转换为“并发”版本。