gpt4 book ai didi

c# - 在 .NET 中创建阻塞 Queue

转载 作者:IT王子 更新时间:2023-10-29 03:30:57 31 4
gpt4 key购买 nike

我有一个场景,我有多个线程添加到一个队列,多个线程从同一个队列读取。如果队列达到特定大小,所有填充队列的线程将在添加时被阻塞,直到从队列中删除一个项目。

下面的解决方案是我现在正在使用的,我的问题是:如何改进?在我应该使用的 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();
}
}
}

最佳答案

这看起来很不安全(很少同步);怎么样:

class SizeQueue<T>
{
private readonly Queue<T> queue = new Queue<T>();
private readonly int maxSize;
public SizeQueue(int maxSize) { this.maxSize = maxSize; }

public void Enqueue(T item)
{
lock (queue)
{
while (queue.Count >= maxSize)
{
Monitor.Wait(queue);
}
queue.Enqueue(item);
if (queue.Count == 1)
{
// wake up any blocked dequeue
Monitor.PulseAll(queue);
}
}
}
public T Dequeue()
{
lock (queue)
{
while (queue.Count == 0)
{
Monitor.Wait(queue);
}
T item = queue.Dequeue();
if (queue.Count == maxSize - 1)
{
// wake up any blocked enqueue
Monitor.PulseAll(queue);
}
return item;
}
}
}

(编辑)

实际上,您需要一种方法来关闭队列,以便读者开始干净地退出 - 可能类似于 bool 标志 - 如果设置,一个空队列只会返回(而不是阻塞):

bool closing;
public void Close()
{
lock(queue)
{
closing = true;
Monitor.PulseAll(queue);
}
}
public bool TryDequeue(out T value)
{
lock (queue)
{
while (queue.Count == 0)
{
if (closing)
{
value = default(T);
return false;
}
Monitor.Wait(queue);
}
value = queue.Dequeue();
if (queue.Count == maxSize - 1)
{
// wake up any blocked enqueue
Monitor.PulseAll(queue);
}
return true;
}
}

关于c# - 在 .NET 中创建阻塞 Queue<T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/530211/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com