如何使自定义线程安全通用列表返回C#中的整个列表?

Jef*_*eff 5 c# list generic-list thread-safety

我是一个线程菜鸟,我正在尝试用C#(.NET 3.5 SP1)编写一个自定义线程安全通用列表类.我已经阅读了为什么线程安全集合如此困难?.在查看了类的要求后,我想我只需要安全地添加到列表中并返回列表.该示例几乎显示了我想要的所有内容,但它缺少返回列表方法,因此我编写了自己的公共方法,如下所示:

更新:基于给出的建议我已经审查了我的要求,因此将课程简化为如下:

public sealed class ThreadSafeList<T>
{
    private readonly IList<T> list = new List<T>();
    private readonly object lockable = new object();

    public void Add(T t)
    {
        lock (lockable)
        {
            list.Add(t);
        }
    }

    public IList<T> GetSnapshot()
    {
        IList<T> result;
        lock (lockable)
        {
            result = new List<T>(list);
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*son 2

同意@jrista。您需要解决一个语义问题,为什么它被称为Translate()?意图是什么?

A - 当前代码 - 返回内部列表的只读包装器

return new ReadOnlyCollection<T>(list);
Run Code Online (Sandbox Code Playgroud)

如果原始列表发生更改并且另一个线程正在迭代列表,您仍然会遇到线程问题。只要您意识到这一点,这就不是什么大问题。

B - 只读副本。

return new List<T>(list).AsReadOnly();
Run Code Online (Sandbox Code Playgroud)

该列表没有线程问题,因为没有任何内容修改新列表。唯一的引用是由ReadOnlyCollection<T>包装器保存的。

C - 普通(可写)副本

return new List<T>(list);
Run Code Online (Sandbox Code Playgroud)

返回一个新的列表,调用者可以对其列表做他们想做的事情,而不会影响原始列表,并且对原始列表的更改不会影响此列表。


如果另一个消费者获取列表的副本然后修改他们的副本,这有什么关系吗?消费者需要看到列表的变化吗?您只需要一个线程安全的枚举器吗?

public IEnumerator<T> ThreadSafeEnumerator()
{
    List<T> copy;
    lock(lockable)
        copy = new List<T>(list);

    foreach (var value in copy)
        yield return value;
}
Run Code Online (Sandbox Code Playgroud)