我喜欢usr关于使用TPL Dataflow的建议。如果您有能力为项目添加外部依赖项(TPL Dataflow不是作为.NET框架的一部分分发),那么它为您的问题提供了一个干净的解决方案。
但是,如果您坚持框架所提供的内容,您应该看看BlockingCollection<T>
,它与您试图实施的生产者 - 消费者模式很好地协同工作。
我把一个快速的.NET 4.0例子抛在一起,以说明如何在你的场景中使用它。这不是很瘦,因为它有很多电话Console.WriteLine()
。但是,如果你把所有的混乱都解决了,那就非常简单了。
在它的中心是一个BlockingCollection<Action>
,它获取Action
代表添加到它从任何线程,和一个线程专用于出队,并在它们被添加的确切顺序执行这些Action
小号顺序。
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace SimpleProducerConsumer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main thread id is {0}.", Thread.CurrentThread.ManagedThreadId);
using (var blockingCollection = new BlockingCollection<Action>())
{
// Start our processing loop.
var actionLoop = new Thread(() =>
{
Console.WriteLine(
"Starting action loop on thread {0} (dedicated action loop thread).",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread);
// Dequeue actions as they become available.
foreach (var action in blockingCollection.GetConsumingEnumerable())
{
// Invoke the action synchronously
// on the "actionLoop" thread.
action();
}
Console.WriteLine("Action loop terminating.");
});
actionLoop.Start();
// Enqueue some work.
Console.WriteLine("Enqueueing action 1 from thread {0} (main thread).", Thread.CurrentThread.ManagedThreadId);
blockingCollection.Add(() => SimulateWork(1));
Console.WriteLine("Enqueueing action 2 from thread {0} (main thread).", Thread.CurrentThread.ManagedThreadId);
blockingCollection.Add(() => SimulateWork(2));
// Let's enqueue it from another thread just for fun.
var enqueueTask = Task.Factory.StartNew(() =>
{
Console.WriteLine(
"Enqueueing action 3 from thread {0} (task executing on a thread pool thread).",
Thread.CurrentThread.ManagedThreadId);
blockingCollection.Add(() => SimulateWork(3));
});
// We have to wait for the task to complete
// because otherwise we'll end up calling
// CompleteAdding before our background task
// has had the chance to enqueue action #3.
enqueueTask.Wait();
// Tell our loop (and, consequently, the "actionLoop" thread)
// to terminate when it's done processing pending actions.
blockingCollection.CompleteAdding();
Console.WriteLine("Done enqueueing work. Waiting for the loop to complete.");
// Block until the "actionLoop" thread terminates.
actionLoop.Join();
Console.WriteLine("Done. Press Enter to quit.");
Console.ReadLine();
}
}
private static void SimulateWork(int actionNo)
{
Thread.Sleep(500);
Console.WriteLine("Finished processing action {0} on thread {1} (dedicated action loop thread).", actionNo, Thread.CurrentThread.ManagedThreadId);
}
}
}
,输出是:
0.016s: Main thread id is 10.
0.025s: Enqueueing action 1 from thread 10 (main thread).
0.026s: Enqueueing action 2 from thread 10 (main thread).
0.027s: Starting action loop on thread 11 (dedicated action loop thread).
0.028s: Enqueueing action 3 from thread 6 (task executing on a thread pool thread).
0.028s: Done enqueueing work. Waiting for the loop to complete.
0.527s: Finished processing action 1 on thread 11 (dedicated action loop thread).
1.028s: Finished processing action 2 on thread 11 (dedicated action loop thread).
1.529s: Finished processing action 3 on thread 11 (dedicated action loop thread).
1.530s: Action loop terminating.
1.532s: Done. Press Enter to quit.
您有效地不能使用Thread.Abort的。在SO上搜索以找到关于原因的一些讨论。 – usr
您确定要在ASP.NET中执行此操作吗?这听起来像是在服务器上运行并独立于客户端浏览器运行的东西。 –
@usr好的。谢谢你的建议。 – My2ndLovE