65.9K
CodeProject 正在变化。 阅读更多。
Home

线程安全的通用队列类

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2009 年 10 月 2 日

CPOL

2分钟阅读

viewsIcon

16745

线程安全的通用队列类

最近我一直在使用标准的 Thread 类、工作队列和新的 PLINQ (并行 LINQ) 进行大量的多线程工作。大多数内置泛型集合(Queue<>List<>Dictionary<> 等)的问题在于它们不是线程安全的。

我创建了一个线程安全集合库,它允许我使用标准的泛型集合操作(foreach、LINQ 等),同时保持线程安全。

此库中的类继承自相应的 集合接口IEnumerableICollection 等)。每个类也具有其原始非线程安全类所具有的所有函数和属性。

您可以下载整个库的副本,其中包含对线程安全 List<>Dictionary<>Queue<> 的支持,请访问:线程安全泛型集合

TQueue<> 示例

我们需要做的第一件事是为 TQueue 创建一个容器和一个线程锁对象。我通常更喜欢使用 ReaderWriterLockSlim,因为它轻量级且速度快。

/// <summary> 
/// The private q which holds the actual data 
/// </summary> 
private readonly Queue<T> m_Queue; 

/// <summary> 
/// Lock for the Q 
/// </summary> 
private readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); 

就像标准的 Queue 一样,我们为初始化提供了三个重载。这些重载允许创建空的 Queue、具有指定容量的 Queue,或者使用初始 IEnumerable 集合来填充 Queue

/// <summary> 
/// Initializes the Queue 
/// </summary> 
public TQueue() 
{ 
    m_Queue = new Queue<T>(); 
} 
  
/// <summary> 
/// Initializes the Queue 
/// </summary> 
/// <param name="capacity">the initial number of elements the queue can contain</param> 
public TQueue(int capacity) 
{ 
    m_Queue = new Queue<T>(capacity); 
} 

/// <summary> 
/// Initializes the Queue 
/// </summary> 
/// <param name="collection">the collection whose 
/// members are copied to the Queue</param> 
public TQueue(IEnumerable<T> collection) 
{ 
    m_Queue = new Queue<T>(collection); 
} 

下一个函数可能是最重要的一个。GetEnumerator()ForEach 循环期间使用,并返回集合中的下一个项目。 遵循微软线程安全枚举器的示例,我们首先获取当前容器 Queue 的副本,然后使用此副本进行迭代。 您会注意到在获取容器 Queue 副本之前使用 Read 锁。

/// <summary> 
/// Returns an enumerator that enumerates through the collection 
/// </summary> 
public IEnumerator<T> GetEnumerator() 
{ 
    Queue<T> localQ; 
  
    // init enumerator 
    LockQ.EnterReadLock(); 
    try 
    { 
        // create a copy of m_TList 
        localQ = new Queue<T>(m_Queue); 
    } 
    finally 
    { 
        LockQ.ExitReadLock(); 
    } 
  
    // get the enumerator 
    foreach (T item in localQ) 
        yield return item; 
} 

一个 Queue 必须包含一个 Enqueue 和一个 Dequeue,用于向集合中添加和删除项目。 就像在每个其他函数中一样,我们使用锁来保护我们的数据访问。

/// <summary> 
/// Adds an item to the queue 
/// </summary> 
/// <param name="item">the item to add to the queue</param> 
public void Enqueue(T item) 
{ 
    LockQ.EnterWriteLock(); 
    try 
    { 
        m_Queue.Enqueue(item); 
    } 
  
    finally 
    { 
        LockQ.ExitWriteLock(); 
    } 
} 
/// <summary> 
/// Removes and returns the item in the beginning of the queue 
/// </summary> 
public T Dequeue() 
{ 
    LockQ.EnterWriteLock(); 
    try 
    { 
        return m_Queue.Dequeue(); 
    } 
  
    finally 
    { 
        LockQ.ExitWriteLock(); 
    } 
} 

我发现很多时候,我需要一次排队多个项目。 这导致创建了 EnqueueAll 函数。 您会注意到第二个重载正在使用线程安全的 List (TList)。

/// <summary> 
/// Enqueues the list of items 
/// </summary> 
/// <param name="ItemsToQueue">list of items to enqueue</param> 
public void EnqueueAll(IEnumerable<T> ItemsToQueue) 
{ 
    LockQ.EnterWriteLock(); 
    try 
    { 
        // loop through and add each item 
        foreach (T item in ItemsToQueue) 
            m_Queue.Enqueue(item); 
    } 
    finally 
    { 
        LockQ.ExitWriteLock(); 
    } 
} 

/// <summary> 
/// Enqueues the list of items 
/// </summary> 
/// <param name="ItemsToQueue">list of items to enqueue</param> 
public void EnqueueAll(TList<T> ItemsToQueue) 
{ 
    LockQ.EnterWriteLock(); 
    try 
    { 
        // loop through and add each item 
        foreach (T item in ItemsToQueue) 
            m_Queue.Enqueue(item); 
    } 
  
    finally 
    { 
        LockQ.ExitWriteLock(); 
    } 
} 

而且,由于我们有一个 EnqueueAll,我也发现需要一次性地从队列中取出所有项目。 DequeueAll 返回一个线程安全的列表 (TList),而不是标准的 List

/// <summary> 
/// Dequeues all the items and returns them as a thread safe list 
/// </summary> 
public TList<T> DequeueAll() 
{ 
    LockQ.EnterWriteLock(); 
    try 
    { 
        // create return object 
        TList<T> returnList = new TList<T>(); 
  
        // dequeue until everything is out 
        while (m_Queue.Count > 0) 
            returnList.Add(m_Queue.Dequeue()); 
  
        // return the list 
        return returnList; 
    } 
    finally 
    { 
        LockQ.ExitWriteLock(); 
    } 
} 

SocialTwist Tell-a-Friend

没有相关文章。

相关文章由 Yet Another Related Posts 插件 提供。


© . All rights reserved.