是List <t> .Contains()线程安全调用 - C#</t>

时间:2009-04-10 18:25:26

标签: c# thread-safety

我的理解是,如果您在C#中使用通用列表(List),它可以支持多个并发读取器,但只能支持一个编写器。当您在混合中引入编写器时,还必须提供同步构造以使操作线程安全。

List.Contains是否被视为读取操作?换句话说,如果我调用此方法,我是否需要担心作者可能同时写入此列表?

10 个答案:

答案 0 :(得分:23)

是的,你应该。基本上我会同步任何操作,如果列表可能同时用于写入。

通常我发现集合分为两类 - 一类是创建的,初始化的,然后再也没有改变过(线程安全的),另一类是随时间变化的(不是线程安全的,锁定所有访问)。

答案 1 :(得分:4)

如果您使用Reflector检查代码,则可以得到如下内容:

public bool Contains(T item)
    {
        if (item == null)
        {
            for (int j = 0; j < this._size; j++)
            {
                if (this._items[j] == null)
                {
                    return true;
                }
            }
            return false;
        }
        EqualityComparer<T> comparer = EqualityComparer<T>.Default;
        for (int i = 0; i < this._size; i++)
        {
            if (comparer.Equals(this._items[i], item))
            {
                return true;
            }
        }
        return false;
    }

正如您所看到的,它是对项目的简单迭代,这绝对是一种“读取”操作。如果您仅将其用于读取(并且没有任何改变项目),则无需锁定。如果您开始在单独的线程中修改列表,那么您最需要同步访问。

答案 2 :(得分:2)

List<T>.Contains肯定是一个读取操作。其他一些线程可能会在您阅读时写入集合。

答案 3 :(得分:2)

是的,你一定要担心! List.Contains只获取一个EqualityComparer,然后循环遍历列表包含的所有项目,将作为参数传递的项目与当前迭代索引处的项目进行比较,因此如果列表在迭代时被修改,结果可能是不可预测的。

答案 4 :(得分:1)

根据doc ...

通过集合枚举本质上不是一个线程安全的过程。

所以,我会说不,这不是线程安全的。你应该锁定它。

答案 5 :(得分:1)

可以安全地假设这不是线程安全操作。 MSDN description总结了它:

  

...此方法使用集合   对象的Equals和CompareTo方法   在项目上确定是否项目   存在。

因此,在读取操作之后是比较操作。

答案 6 :(得分:1)

在多线程环境中,您需要确保不会同时写入集合。这是来自反射器的代码,该集合本身并没有为你提供任何锁定,所以它就在你的胜利上。

public bool Contains(T item)
{
    if (item == null)
    {
        for (int j = 0; j < this._size; j++)
        {
            if (this._items[j] == null)
            {
                return true;
            }
        }
        return false;
    }
    EqualityComparer<T> comparer = EqualityComparer<T>.Default;
    for (int i = 0; i < this._size; i++)
    {
        if (comparer.Equals(this._items[i], item))
        {
            return true;
        }
    }
    return false;
}

答案 7 :(得分:0)

如果作者可能同时写作,List.Contains肯定不是线程安全的。你需要用锁来包装它和任何其他的读写。

答案 8 :(得分:0)

它被认为是一个读操作。您不会遇到任何竞争条件,但如果您担心获取最新信息,则可以List volatile

答案 9 :(得分:0)

根据the MSDN documentation

  

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

ReaderWriterLock类似乎是为您正在寻找的同步而构建的。