.NET中的线程安全队列(列表)

13

我需要创建一个线程安全的列表,用来添加到Lucene索引中。

以下是线程安全的吗?

public sealed class IndexQueue
{
    static readonly IndexQueue instance = new IndexQueue();
    private List<string> items = new List<string>();

    private IndexQueue() { }

    public static IndexQueue Instance {
        get { return instance; }
    }

    private object padlock = new object();

    public void AddItem(string item) {
        lock (padlock) {
            items.Add(item);
        }
    }
}

即使是从内部列表中获取项目,锁定是否仍然是必需的?

想法是我们将有一个单独的任务运行来从indexqueue中获取项目并将它们添加到lucene索引中。

谢谢
Ben


2
在.NET 4中有线程安全的实现(如果您甚至可以使用4),不确定您是否知道,因为我看到您正在自己编写... http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx - Aaron McIver
谢谢大家。我会看一下 System.Collections.Concurrent。 - Ben Foster
我认为 System.Collections.Concurrent 对你来说可能并不是很有用。它没有 List 的等效物,即使有,你仍然可能需要应用自己的锁定来使项目的枚举具有原子性。这实际上取决于你希望多个线程如何感知枚举。 - Brian Gideon
Brian - ConcurrentQueue正是我们所需要的。它的FIFO行为对我们很有用。然而,正如你所说,我们确实需要在调用Contains<T>时引入锁定,以防止重复项被添加到队列中 - 只是为了防止竞态条件的发生。 - Ben Foster
3个回答

38

你的实现看起来是线程安全的,不过当从items中读取数据时你仍需要进行锁定 - 如果有并发的Add操作,则不能安全地进行读取。如果你需要枚举操作,你也需要在其周围加上锁定,并且这将需要与枚举器一样长时间存在。

如果你可以使用 .net 4,我强烈建议查看System.Collections.Concurrent 命名空间。它具有经过充分测试和相当高效的集合,它们是线程安全的,并且实际上是针对多线程访问进行优化的。


4
即使从内部列表中获取项目,是否也需要进行锁定?
当您进行修改时,List类在多线程下是不安全的。如果满足以下条件,则需要锁定:
- 您从多个线程使用该类的单个实例。 - 当您修改或读取列表时,列表的内容可能会更改。
假设第一个条件为真,否则您将不会问这个问题。显然第二个条件为真,因为Add方法会修改列表。所以,是的,您需要锁定它。
当您向类添加允许您读回项目的方法时,也需要锁定,并且重要的是您必须使用与AddItem中相同的锁对象。

2

是的,虽然检索不是本质上不安全的操作,但如果您同时也在向列表中写入内容,那么就有可能在写入过程中进行检索。

特别是如果这将像传统队列一样运作,其中检索实际上将从列表中删除已检索的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接