我正在尝试为我的工作设计一个具有很多设计要求的线程池.这对于工作软件来说是一个真正的问题,这是一项艰巨的任务.我有一个有效的实现,但我想把它扔到SO,看看人们可以提出什么有趣的想法,以便我可以比较我的实现,看看它是如何叠加的.我试图尽可能地满足要求.
线程池需要执行一系列任务.任务可以是短时间运行(<1秒)或长时间运行(数小时或数天).每个任务都有一个相关的优先级(从1 =非常低到5 =非常高).任务可以在其他任务运行时随时到达,因此当它们到达时,线程池需要选择这些并在线程可用时安排它们.
任务优先级完全独立于任务长度.实际上,如果不运行任务就无法确定任务可以运行多长时间.
某些任务受CPU限制,而有些任务受IO限制.事先不可能知道给定的任务是什么(虽然我猜在任务运行时可能会检测到).
线程池的主要目标是最大化吞吐量.线程池应该有效地使用计算机的资源.理想情况下,对于CPU绑定任务,活动线程的数量将等于CPU的数量.对于IO绑定任务,应分配比CPU更多的线程,以便阻塞不会过度影响吞吐量.最大限度地减少锁的使用和使用线程安全/快速容器非常重要.
通常,您应该以更高的CPU优先级运行更高优先级的任务(参考:SetThreadPriority).较低优先级的任务不应"阻止"更高优先级的任务运行,因此如果在所有低优先级任务运行时出现更高优先级的任务,则优先级较高的任务将运行.
任务具有与其关联的"最大运行任务"参数.每种类型的任务只允许一次最多运行该任务的许多并发实例.例如,我们可能在队列中有以下任务:
A - 1000个实例 - 低优先级 - 最大任务1
B - 1000个实例 - 低优先级 - 最大任务1
C - 1000个实例 - 低优先级 - 最大任务1
工作实现只能同时运行(最多)1 A,1 B和1 C.
它需要在Windows XP,Server 2003,Vista和Server 2008(最新的服务包)上运行.
作为参考,我们可能会使用以下界面:
namespace ThreadPool { class Task { public: Task(); void run(); }; class ThreadPool { public: ThreadPool(); ~ThreadPool(); void run(Task *inst); void stop(); }; }
DrPizza.. 5
那么我们将选择什么作为这个的基本构建块.Windows有两个看起来很有前途的构建块: - I/O完成端口(IOCP)和异步过程调用(APC).这两个都为我们提供了FIFO排队,而不必执行显式锁定,并且在调度程序等位置具有一定量的内置OS支持(例如,IOCP可以避免某些上下文切换).
APC可能稍微适合一些,但我们必须对它们略微小心,因为它们不是很"透明".如果工作项执行可警告的等待(:: SleepEx,:: WaitForXxxObjectEx等)并且我们意外地将APC分派给线程,则新分派的APC将接管该线程,暂停先前执行的APC,直到新的APC为止.完了.这对我们的并发要求不利,并且可能使堆栈溢出更有可能.
那么我们将选择什么作为这个的基本构建块.Windows有两个看起来很有前途的构建块: - I/O完成端口(IOCP)和异步过程调用(APC).这两个都为我们提供了FIFO排队,而不必执行显式锁定,并且在调度程序等位置具有一定量的内置OS支持(例如,IOCP可以避免某些上下文切换).
APC可能稍微适合一些,但我们必须对它们略微小心,因为它们不是很"透明".如果工作项执行可警告的等待(:: SleepEx,:: WaitForXxxObjectEx等)并且我们意外地将APC分派给线程,则新分派的APC将接管该线程,暂停先前执行的APC,直到新的APC为止.完了.这对我们的并发要求不利,并且可能使堆栈溢出更有可能.