线程安全的通用队列类
线程安全的通用队列类
最近我一直在使用标准的 Thread
类、工作队列和新的 PLINQ (并行 LINQ) 进行大量的多线程工作。大多数内置泛型集合(Queue<>
、List<>
、Dictionary<>
等)的问题在于它们不是线程安全的。
我创建了一个线程安全集合库,它允许我使用标准的泛型集合操作(foreach
、LINQ 等),同时保持线程安全。
此库中的类继承自相应的 集合接口
(IEnumerable
、ICollection
等)。每个类也具有其原始非线程安全类所具有的所有函数和属性。
您可以下载整个库的副本,其中包含对线程安全 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();
}
}
没有相关文章。
相关文章由 Yet Another Related Posts 插件 提供。