【发布时间】:2010-10-06 12:34:44
【问题描述】:
我有一个场景,我有多个线程添加到一个队列中,并且多个线程从同一个队列中读取。如果队列达到特定大小正在填充队列的所有线程将在添加时被阻塞,直到从队列中删除项目。
下面的解决方案是我现在正在使用的,我的问题是:如何改进?在我应该使用的 BCL 中是否存在已经启用此行为的对象?
internal class BlockingCollection<T> : CollectionBase, IEnumerable
{
//todo: might be worth changing this into a proper QUEUE
private AutoResetEvent _FullEvent = new AutoResetEvent(false);
internal T this[int i]
{
get { return (T) List[i]; }
}
private int _MaxSize;
internal int MaxSize
{
get { return _MaxSize; }
set
{
_MaxSize = value;
checkSize();
}
}
internal BlockingCollection(int maxSize)
{
MaxSize = maxSize;
}
internal void Add(T item)
{
Trace.WriteLine(string.Format("BlockingCollection add waiting: {0}", Thread.CurrentThread.ManagedThreadId));
_FullEvent.WaitOne();
List.Add(item);
Trace.WriteLine(string.Format("BlockingCollection item added: {0}", Thread.CurrentThread.ManagedThreadId));
checkSize();
}
internal void Remove(T item)
{
lock (List)
{
List.Remove(item);
}
Trace.WriteLine(string.Format("BlockingCollection item removed: {0}", Thread.CurrentThread.ManagedThreadId));
}
protected override void OnRemoveComplete(int index, object value)
{
checkSize();
base.OnRemoveComplete(index, value);
}
internal new IEnumerator GetEnumerator()
{
return List.GetEnumerator();
}
private void checkSize()
{
if (Count < MaxSize)
{
Trace.WriteLine(string.Format("BlockingCollection FullEvent set: {0}", Thread.CurrentThread.ManagedThreadId));
_FullEvent.Set();
}
else
{
Trace.WriteLine(string.Format("BlockingCollection FullEvent reset: {0}", Thread.CurrentThread.ManagedThreadId));
_FullEvent.Reset();
}
}
}
【问题讨论】:
-
.Net 如何有内置类来帮助解决这种情况。此处列出的大多数答案都已过时。请参阅底部的最新答案。查看线程安全的阻塞集合。答案可能已经过时,但它仍然是一个好问题!
-
我认为学习 Monitor.Wait/Pulse/PulseAll 仍然是一个好主意,即使我们在 .NET 中有新的并发类。
-
同意@thewpfguy。您需要了解幕后的基本锁定机制。另外值得注意的是,Systems.Collections.Concurrent 直到 2010 年 4 月才存在,然后仅在 Visual Studio 2010 及更高版本中存在。绝对不是 VS2008 支持的选项...
-
如果您现在正在阅读本文,请查看 System.Threading.Channels 以了解针对 .NET Core 和 .NET 的多写入器/多读取器、有界、可选阻塞实现标准。
标签: c# .net multithreading collections queue