我需要实现一种任务缓冲区。基本要求是:
我正在考虑使用如下的队列来实现它。希望得到有关实施的反馈。还有其他更明智的想法来实现这样的事情吗?
public class TestBuffer
{
private readonly object queueLock = new object();
private Queue<Task> queue = new Queue<Task>();
private bool running = false;
public TestBuffer()
{
}
public void start()
{
Thread t = new Thread(new ThreadStart(run));
t.Start();
}
private void run()
{
running = true;
bool run = true;
while(run)
{
Task task = null;
// Lock queue before doing anything
lock (queueLock)
{
// If the queue is currently empty and it is still running
// we need to wait until we're told something changed
if (queue.Count == 0 && running)
{
Monitor.Wait(queueLock);
}
// Check there is something in the queue
// Note - there might not be anything in the queue if we were waiting for something to change and the queue was stopped
if (queue.Count > 0)
{
task = queue.Dequeue();
}
}
// If something was dequeued, handle it
if (task != null)
{
handle(task);
}
// Lock the queue again and check whether we need to run again
// Note - Make sure we drain the queue even if we are told to stop before it is emtpy
lock (queueLock)
{
run = queue.Count > 0 || running;
}
}
}
public void enqueue(Task toEnqueue)
{
lock (queueLock)
{
queue.Enqueue(toEnqueue);
Monitor.PulseAll(queueLock);
}
}
public void stop()
{
lock (queueLock)
{
running = false;
Monitor.PulseAll(queueLock);
}
}
public void handle(Task dequeued)
{
dequeued.execute();
}
}
答案 0 :(得分:7)
您可以使用开箱即用的BlockingCollection实际处理此问题。
它旨在拥有一个或多个生产者,以及一个或多个消费者。在您的情况下,您将拥有多个生产者和一个消费者。
当您收到停止信号时,请使用该信号处理程序
消费者线程将继续运行,直到删除并处理所有排队的项目,然后它将遇到BlockingCollection完成的情况。当线程遇到这种情况时,它就会退出。
答案 1 :(得分:5)
实际上,您应该考虑ConcurrentQueue,即FIFO。如果不合适,请在Thread-Safe Collections中尝试一些亲戚。通过使用这些,您可以避免一些风险。
答案 2 :(得分:1)
我建议你看看TPL DataFlow。 BufferBlock是您正在寻找的,但它提供了更多。
答案 3 :(得分:1)
看看我的线程安全FIFO队列的轻量级实现,它不会阻塞任何东西并使用线程池 - 更好的是在大多数情况下创建自己的线程。 https://github.com/Gentlee/SerialQueue
用法:
var queue = new SerialQueue();
var result = await queue.Enqueue(LongRunningWork);
答案 4 :(得分:0)
您可以在.NET 3.5上使用Rx。它可能永远不会出现RC,但我相信它是稳定的*并且被许多生产系统使用。如果您不需要Subject,您可能会发现.NET 3.5的原语(如并发集合),您可以使用.NET Framework中未附带的原型,直到4.0。
Alternative to Rx (Reactive Extensions) for .net 3.5
* - Nit挑选者的角落:除了高级时间窗口,超出范围,但缓冲区(按计数和时间),排序和调度程序都是稳定的。