11

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

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

4

10 回答 10

23

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

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

于 2009-04-10T18:30:16.687 回答
5

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

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

于 2009-04-10T18:38:57.010 回答
2

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

于 2009-04-10T18:29:41.713 回答
2

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

于 2009-04-10T18:30:28.403 回答
1

根据医生...

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

所以,我会说不,它不是线程安全的。你应该把它锁起来。

于 2009-04-10T18:29:49.793 回答
1

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

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

所以,读操作之后是比较操作。

于 2009-04-10T18:30:36.140 回答
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;
}
于 2009-04-10T18:32:41.300 回答
0

如果一个作家可能同时在写作,那么 List.Contains 绝对不是线程安全的。您需要用锁包装它和任何其他读写操作。

于 2009-04-10T18:30:06.907 回答
0

它被认为是读取操作。您不会遇到任何竞争条件,但如果您担心获得最新的,您可以制作List volatile.

于 2009-04-10T18:32:44.763 回答
0

根据MSDN 文档

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

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

于 2009-04-10T18:32:55.057 回答