本文是翻译CodeProject上的一篇文章的,由于自己水平有限,许多地方有谬误.希望大家指正.在这之前,我也不知道这片文章是否有被翻译过,只是自己在学习线程池的时候发现了这篇好文章(原文地址:http://www.codeproject.com/KB/threads/ExtendedThreadPool.aspx),就顺便翻译了下.并下在了源码调试了下,感觉原作者确实有些先进的思路.本篇翻译的目的是想在这个基础上了解下线程池的应用和扩展.
源码可以到原地址去下载,要注册用户的哦^0^
下面是正文:
前言
线程池的类型有许多:Smart线程池, BlackHen.Threading,但是没有一个线程池支持扩展,所有的线程池的编码都是有难度的,工作起来又有一定难度。我尽力解决以下问题:
- 线程池的可扩展和可配置
- 线程池应用尽可能简单化
因此,我创建了Extended Thread Pool(作者有意思把该项目作为开源发展)。此线程池是以C# 3.0环境下创建的。
Extended Thread Pool 的特征
- IoC 支持(使用了Unity)
- 扩展队列
- 扩展任务项
- 限制了工作线程的最大数量
- 动态线程分配
- 线程优先级支持
- 扩展日志
Extended Thread Pool的设计
- ITaskItem 表示任务
- ITaskQueue 表示任务的队列逻辑
- ITaskQueueController 表示消费者和生产者之间的通信逻辑(线程安全)
- WorkThread 表示线程执行
- ExtendedThreadPool 控制线程的执行
让我们来深入了解每个类:
- ITaskItem 表示要完成工作
-
- public interface ITaskItem
- {
- ThreadPriority Priority { get; }
- void DoWork();
- }
- ThreadPriority – WorkThread 的优先级,可以在每个任务中指定
- ITaskQueue 另一个管理任务队列的接口
-
- public interface ITaskQueue
- {
- int Count { get; }
- void Enqueue(ITaskItem item);
- ITaskItem Dequeue();
- }
-
- ITaskQueueController提供了消费者和生产者之间的通信逻辑
-
- public interface ITaskQueueController : IDisposable
- {
- int ConsumersWaiting { get; }
- void Enqueue(ITaskItem item);
- ITaskItem Dequeue();
- }
从ITaskQueueController接口派生了两个队列控制对象:
- DefaultTaskQueueController
- BoundedTaskQueueController
Default Task Queue Controller
DefaultTaskQueueController对与ITaskQueue是线程安全的封装:
- public class DefaultTaskQueueController : TaskQueueControllerBase
- {
- public DefaultTaskQueueController(ITaskQueue taskQueue)
- : base(taskQueue)
- {
- }
- #region Overrides of TaskQueueControllerBase
- public override void Enqueue(ITaskItem item)
- {
- lock (_locker)
- {
- _taskQueue.Enqueue(item);
- if (_consumersWaiting > 0)
- Monitor.PulseAll(_locker);
- }
- }
- public override ITaskItem Dequeue()
- {
- ITaskItem taskItem;
- lock (_locker)
- {
- while (_taskQueue.Count == 0 && !_isDispose)
- {
- _consumersWaiting++;
- Monitor.Wait(_locker);
- _consumersWaiting--;
- }
- if (_isDispose)
- return null;
- taskItem = _taskQueue.Dequeue();
- }
- return taskItem;
- }
- #endregion
- }
Bounded Task Queue Controller
BoundedTaskQueueController(线程安全)如果生产者任务或者创建项的任务比消费者的处理速度快,系统将会无限的消耗内存。BoundedTaskQueueController允许限制队列的大小来限制生产者的越界。
- public class BoundedTaskQueueController : TaskQueueControllerBase
- {
- private readonly int _maxTasksCount;
- private int _producersWaiting;
- public BoundedTaskQueueController(ITaskQueue taskQueue, int maxTasksCount)
- : base(taskQueue)
- {
- if (maxTasksCount < 1)
- throw new ArgumentException("MaxTasksCount should be greater 0");
- _maxTasksCount = maxTasksCount;
- }
- public override void Enqueue(ITaskItem item)
- {
- lock (_locker)
- {
- while (_taskQueue.Count == (_maxTasksCount - 1) && !_isDispose)
- {
- _producersWaiting++;
- Monitor.Wait(_locker);
- _producersWaiting--;
- }
- _taskQueue.Enqueue(item);
- if (_consumersWaiting > 0)
- Monitor.PulseAll(_locker);
- }
- }
- public override ITaskItem Dequeue()
- {
- ITaskItem taskItem;
- lock (_locker)
- {
- while (_taskQueue.Count == 0 && !_isDispose)
- {
- _consumersWaiting++;
- Monitor.Wait(_locker);
- _consumersWaiting--;
- }
- if (_isDispose)
- return null;
- taskItem = _taskQueue.Dequeue();
- if (_producersWaiting > 0)
- Monitor.PulseAll(_locker);
- }
- return taskItem;
- }
- }
Extended Thread Pool
ExtendedThreadPool类管理接口ITaskQueueController。AddTask方法用来添加任务到任务通道中去。如果最大的线程限制未达到并且ConsamersWaitin = 0,WorkThread类的新实例将被创建。
- public void AddTask(ITaskItem item)
- {
- if (item.IsNull())
- throw new ArgumentNullException("item");
- if (!(Enum.IsDefined(typeof (ThreadPriority), item.Priority)))
- throw new ArgumentException("priority");
- TaskQueueController.Enqueue(item);
- if (IsStartNewWorker())
- CreateWorkThread();
- }
Work Thread
WorkThread类,执行任务项和提供日志记录的。
- public void Start()
- {
- while (_isRun)
- {
- try
- {
- ITaskItem item = _taskQueueController.Dequeue();
- if (item.IsNull())
- continue;
- DoWork(item);
- }
- catch (Exception ex)
- {
- _logger.Error(ex.Message);
- }
- }
- }
Thread Pool Extensibility
ExtendedThreadPool类提供了Ioc支持,ITaskQueueController接口标记了Dependency属性。
- [Dependency]
- public ITaskQueueController TaskQueueController { private get; set; }
如果你需要更加强大的任务队列,就必须实现ITaskQueue接口,并不需要担心线程安全的问题;也可以创建ITaskQueueController。我使用Unity来配置ExtendedThreadPool。
例子
在其中一个项目中,我使用了multi-threading进行MSMQ交互。SampleTask派生了接口ITaskItem,可以从项目CoreDefaultMsmqSample中了解详情。
- public void DoWork()
- {
- using (var transaction = new MessageQueueTransaction())
- {
- try
- {
- transaction.Begin();
- Message msmqMessage =
- _queue.Receive(TimeSpan.FromMilliseconds(500), transaction);
- if (msmqMessage != null)
- {
- var message = (ExternalMessage) msmqMessage.Body;
- LogManager.GetLogger(GetType()).Info("Task has been " +
- "done, info {0}".FormatWith(message.Data));
- //Do work
- Thread.Sleep(1000);
- }
- }
- catch (Exception ex)
- {
- transaction.Abort();
- LogManager.GetLogger(GetType()).Error(ex.Message);
- return;
- }
- transaction.Commit();
- }
- }
总结
作者考虑到了线程池的可配置性和扩展性,在引用这些代码后,写出的线程应用会非常简洁,且不需要考虑线程之间的复杂操作.如果,你觉得有写模块是你不需要的,比如日志模块或者IoC模块(这是什么模块我也不清楚),可以自行把代码删除掉,希望原作者会继续他的思路完善这个框架.