代码之家  ›  专栏  ›  技术社区  ›  adeel825

is list<t>.contains()一个线程安全调用-c#

  •  11
  • adeel825  · 技术社区  · 15 年前

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

    是否将list.contains视为读取操作?换句话说,如果我调用这个方法,我是否需要担心一个作家可能同时在写这个列表?

    10 回复  |  直到 15 年前
        1
  •  23
  •   Jon Skeet    15 年前

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

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

        2
  •  4
  •   Erich Mirabal    15 年前

    如果使用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;
        }
    

    如您所见,它是对项目的简单迭代,这绝对是一个“读取”操作。如果您只将它用于读取(没有任何东西会改变项目),那么就不需要锁定它。如果您开始在一个单独的线程中修改列表,那么您肯定需要同步访问。

        3
  •  2
  •   em70    15 年前

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

        4
  •  2
  •   Andrew Hare    15 年前

    List<T>.Contains 当然是一个读取操作。在您阅读该集合时,可能有其他线程正在写入该集合。

        5
  •  1
  •   JP Alioto    15 年前

    根据 doc

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

    所以,我会说不,这是不安全的。你应该把它锁上。

        6
  •  1
  •   spoulson    15 年前

    假设这不是线程安全操作是安全的。这个 MSDN description 总结一下:

    …此方法使用集合_ 对象Equals和CompareTo方法 在项目上确定项目 存在。

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

        7
  •  1
  •   J.W.    15 年前

    在多线程环境中,您需要确保不会同时向集合中写入内容。这是来自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;
    }
    
        8
  •  0
  •   Michael    15 年前

    如果编写器可能同时在编写,则list.contains绝对不是线程安全的。你需要用锁包装它和其他读写操作。

        9
  •  0
  •   Alexander Kahoun    15 年前

    它被认为是一个读取操作。你不会遇到任何比赛条件,但是如果你想得到最新的,你可以 List volatile .

        10
  •  0
  •   Greg    15 年前

    根据 the MSDN documentation :

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

    这个 ReaderWriterLock 类似乎是为您要查找的同步而构建的。