Java ExecutorService.newSingleThreadExecutor()的C#等价物,或者:如何序列化对资源的多线程访问

时间:2011-01-11 19:31:05

标签: c# .net multithreading concurrency

我的代码中有几种情况,各种线程可以创建工作项,由于各种原因,不应该并行完成。我想确保工作以FIFO方式完成,无论它来自哪个线程。在Java中,我将工作项放在单线程ExecutorService上;在C#中是否有等价物?我用Queue和一堆lock(){}块拼凑了一些东西,但是能够使用现成的和经过测试的东西会很棒。

更新:是否有人有使用System.Threading.Tasks的经验?它有这种解决方案吗?我正在写一个Monotouch应用程序,所以谁知道我是否能找到一个我可以开始工作的移植版本,但它至少应该考虑未来。

更新#2 对于不熟悉我正在谈论的Java库的C#开发人员,基本上我想要一些能让各个线程切换工作项的东西,以便所有这些工作项都能运行在单线程(不是任何调用线程)。


更新,6/201 :如果我现在正在构建一个类似的系统,我可能会根据Reactive Extensions使用Matt Craig's answer。但是,我要离开Zachary Yates' answer被接受的那个,因为如果你在Rx中思考,你可能甚至不会问这个问题,我认为ConcurrentQueue更容易躲到前Rx程序

5 个答案:

答案 0 :(得分:4)

您可以使用ConcurrentQueue,(如果monotouch支持.net 4?)它是线程安全的,我认为实现实际上是无锁的。如果您有一个长时间运行的任务(如在Windows服务中),这非常有效。

通常情况下,您的问题听起来像是有多个生产者只有一个消费者。

var work = new ConcurrentQueue<Item>();
var producer1 = Task.Factory.StartNew(() => {
    work.Enqueue(item); // or whatever your threads are doing
});
var producer2 = Task.Factory.StartNew(() => {
    work.Enqueue(item); // etc
});
var consumer = Task.Factory.StartNew(() => {
    while(running) {
        Item item = null;
        work.TryDequeue(out item);
    }
});
Task.WaitAll(producer1, producer2, consumer);

如果您拥有有限的工作项池,则应使用BlockingCollectionHere's an MSDN page显示所有新的并发集合类型。

答案 1 :(得分:1)

相信这可以使用SynchronizationContext来完成。但是,我只是这样做回发到UI线程,它已经有.NET提供的同步上下文(如果被告知要安装) - 我不知道如何准备它从“vanilla线程”使用“虽然。

我找到的“自定义同步文本提供程序”的一些链接(我没有时间查看这些,不完全理解工作/上下文,也没有任何其他信息):

  1. Looking for an example of a custom SynchronizationContext (Required for unit testing)

  2. http://codeidol.com/csharp/wcf/Concurrency-Management/Custom-Service-Synchronization-Context/

  3. 快乐的编码。

答案 2 :(得分:1)

现在有一种更现代的解决方案 - EventLoopScheduler类。

答案 3 :(得分:0)

不是原生AFAIK,但看看这个: Serial Task Executor; is this thread safe?

答案 4 :(得分:-2)

正如我在评论中所写,您自己发现lock语句可以完成这项工作。

如果您有兴趣获得一个可以简化管理工作项队列的“容器”,请查看ThreadPool类。

我认为,在设计良好的架构中,使用这两个元素(ThreadPool类和lock语句),您可以轻松且成功地序列化对资源的访问。