关于c ++:用于执行具有不同优先级的任意任务的线程池

关于c ++:用于执行具有不同优先级的任意任务的线程池

Thread pool for executing arbitrary tasks with different priorities

我正在尝试为线程池设计一个对我的工作有很多设计要求的设计。对于工作软件而言,这是一个真正的问题,这是一项艰巨的任务。我有一个可行的实现,但是我想把它扔给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和1C。

它需要在Windows XP,Server 2003,Vista和Server 2008(最新Service Pack)上运行。

作为参考,我们可以使用以下接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace ThreadPool
{
    class Task
    {
    public:
        Task();    
        void run();
    };

    class ThreadPool
    {    
    public:
        ThreadPool();
        ~ThreadPool();

        void run(Task *inst);
        void stop();
    };
}

因此,我们将选择什么作为此的基本构建块。 Windows有两个看起来很有希望的构建块:-I / O完成端口(IOCP)和异步过程调用(APC)。 这两种方法都使我们无需进行显式锁定就可以进行FIFO排队,并且在诸如调度程序的地方具有一定数量的内置OS支持(例如,IOCP可以避免某些上下文切换)。

APC可能更合适,但由于它们并不完全"透明",因此我们必须对它们稍加小心。 如果工作项执行可警告的等待(:: SleepEx,:: WaitForXxxObjectEx等),而我们不小心将APC调度到线程,则新调度的APC将接管该线程,暂停先前执行的APC,直到新的APC被 完成。 这对我们的并发要求不利,并且可能使堆栈溢出的可能性更大。


It needs to run on Windows XP, Server 2003, Vista and Server 2008 (latest service packs).

系统内置线程池的哪些功能使其不适合您的任务?如果要使用XP和2003,则不能使用新的闪亮的Vista / 2008池,但仍可以使用QueueUserWorkItem和好友。


@DrPizza:

OK, I'm still a bit unclear about how
you wish the priorities to work. If
the pool is currently running a task
of type A with maximal concurrency of
1 and low priority, and it gets given
a new task also of type A (and maximal
concurrency 1), but this time with a
high priority, what should it do?

这是一个棘手的任务,尽管在这种情况下,我认为只允许低优先级的任务完成就可以了。通常,我们不会看到许多具有不同线程优先级的相同类型的任务。在我们的模型中,实际上可以安全地暂停并稍后在明确定义的点重新启动任务(出于不同的原因),尽管这样做带来的复杂性可能不值得冒险。

通常,只有不同类型的任务才具有不同的优先级。例如:

  • 任务-1000个实例-低优先级
  • B任务-1000个实例-高优先级

假设A任务已经出现并正在运行,然后B任务已经到达,我们希望B任务能够或多或少地立即运行。


@DrPizza - this is a very good question, and one that strikes right to the heart of the problem. There are a few reasons why QueueUserWorkItem and the Windows NT thread pool was ruled out (although the Vista one does look interesting, maybe in a few years).

是的,看起来它已经在Vista中得到了增强,现在功能相当丰富。

好的,对于您希望优先级如何工作,我仍然不清楚。如果该池当前正在运行最大并发性为1且优先级较低的任务,并且为其分配了一个新任务,同时也是一个类型为A的任务(且最大并发性为1),但是这次具有高优先级,它应该怎么做? ?

挂起当前正在执行的A会很麻烦(它可能持有新任务需要执行的锁定,从而使系统死锁)。它不能产生第二个线程,而只能让它并行运行(允许的并发度仅为1)。但是它不能等到低优先级任务完成后才能执行,因为运行时是无限制的,这样做将允许低优先级任务阻止高优先级任务。

我的假设是您追求的是后者的行为?


@DrPizza-这是一个非常好的问题,而这恰恰是问题的核心。排除QueueUserWorkItem和Windows NT线程池的原因有几个(尽管Vista看上去确实很有趣,也许在几年后)。

首先,我们希望更好地控制它的启动和停止时间。我们已经听说,如果NT线程池认为任务运行很短,则不愿意启动新线程。我们可以使用WT_EXECUTELONGFUNCTION,但是我们真的不知道任务是长还是短

其次,如果线程池已被长时间运行的低优先级任务填满,那么高优先级的任务就不会及时运行。 NT线程池没有真正的任务优先级概念,因此我们不能执行QueueUserWorkItem并说"哦,顺便说一句,立即运行"。

第三,(根据MSDN)NT线程池与STA公寓模型不兼容。我不确定这意味着什么,但是我们所有的工作线程都在STA中运行。


推荐阅读

    程序执行linux命令?

    程序执行linux命令?,系统,工作,地址,环境,信息,管理,命令,文件,目录,程序,lin

    linux执行2个命令?

    linux执行2个命令?,工作,系统,基础,命令,基础知识,信息,管理,在线,概念,第一

    linux命令批量执行?

    linux命令批量执行?,系统,代码,工作,周期性,数据,定期,环境,命令,文件,脚本,l

    linux二进制执行命令?

    linux二进制执行命令?,系统,工作,情况,代码,信息,位置,地址,命令,文件,目录,L

    linux执行退出命令?

    linux执行退出命令?,档案,状态,工作,命令,信息,地址,电脑,系统,编辑,文件,lin

    linux中后台执行命令?

    linux中后台执行命令?,系统,状态,暂停,灵活,电脑,网络,服务,第一,名字,命令,l

    linux执行线程命令?

    linux执行线程命令?,系统,工作,线程,软件,服务,管理,信息,环境,名称,命令,lin

    linux执行多条命令?

    linux执行多条命令?,数据,通信,管理,系统,命令,标准,信息,工具,代码,环境,Lin

    linux退出命令未执行?

    linux退出命令未执行?,服务,工具,代码,环境,数据,官网,命令,用户,脚本,字符

    linux动态执行命令?

    linux动态执行命令?,时间,信息,名字,工作,网上,业务,工具,对比,地址,下来,如

    linux命令执行次数?

    linux命令执行次数?,时间,系统,地址,命令,数据,管理,工具,信息,环境,历史,lin

    linux命令一起执行?

    linux命令一起执行?,系统,标准,设备,地方,软件,代码,网站,网络,周期性,命令,l

    查看执行的命令linux?

    查看执行的命令linux?,系统,地址,信息,工作,命令,灵活,网络,名称,情况,状态,

    linux导出执行命令?

    linux导出执行命令?,数据,系统,命令,下来,位置,时间,工具,服务,文件,指令,lin

    linux持续执行命令?

    linux持续执行命令?,连续,定期,密码,系统,状态,命令,任务,文件,程序,前台,lin

    linux隐藏执行的命令?

    linux隐藏执行的命令?,工作,电脑,系统,地址,标准,信息,管理,命令,目录,软件,

    linux在哪执行命令?

    linux在哪执行命令?,电脑,命令,第一,第三,名字,系统,密码,脚本,终端,方法,怎

    js执行linux命令行?

    js执行linux命令行?,密码,系统,服务,项目,环境,工具,软件,设备,管理,平台,lin

    怎么执行linux命令行?

    怎么执行linux命令行?,系统,软件,工具,首页,终端,密码,环境,基础知识,官方

    linux命令换行不执行?

    linux命令换行不执行?,信息,标准,系统,命令,名字,工作,分析,环境,连续,名称,