C ++,当每个工作线程必须执行几项不同的任务时,如何为任务实现线程池

时间:2015-02-23 08:09:33

标签: c++ multithreading threadpool

我正在分析视频流。对于每个新图像(帧),我按顺序执行以下3个任务:

  1. 缩小图像尺寸
  2. 检测面孔
  3. 跟踪图像中最重要的4个面
  4. 为了在4-cpu机器上加速,我使用了4个工作线程。以下列方式

    1. 主要流程获取图像。创建4个工作线程,将图像分割为4个四分之一,每个工作者重新调整其1/4图像像素的大小。主进程等待线程完成并将剩余部分组装成最终图像
    2. 主要流程为面部检测创建了4名新工作人员。我检测到4种类型的面孔(男性,女性,婴儿,狗)。每个工作线程负责一种类型。主进程等待工人完成并组装结果(所有现有面的列表)。
    3. 主要流程为面部跟踪创建了4名新员工。选择4个最重要的面孔,每个工人跟踪1个面部。主要流程等待完成。
    4. 我的实现问题是我没有线程池。在每个视频帧(大约每秒30次)上,主要过程上升并杀死12名工人(4名工人x 3个不同的任务)。所以在线程管理上浪费了很多时间。目前,我使用_beginthreadex()方法为特定任务的工作线程提供午餐

      期望的解决方案:我想只创建一个4个工作线程(每个工作者能够执行所有3个不同的任务)。这些工作人员将在整个视频处理过程中存在。在每个视频帧上,主进程会将图像重新调整大小的任务抛给工作人员,而不是检测和后续跟踪。

      丑陋的实现将是每个工作线程都是一个实现所有3个任务的大功能。主进程只告诉每个worker要执行哪个任务(worker有一个'switch'语句来选择所请求的任务)。这是一个丑陋的解决方案,因为将来我将在管道中有30个不同的任务而不是3个 - 工人的代码将变得巨大。此外,这个解决方案违反了封装规则,因为它要求所有任务驻留在同一个函数中+每个新任务,我需要更改工作者的代码

      一个干净的实现将是主进程为每个worker指定一个函数(要执行的任务)和一些参数。因此,我可以轻松地在我的视频处理管道中添加新任务而无需更改工作程序的代码,因为worker的代码是通用的(执行指向函数的指针并等待带有新指针的请求到达) 但问题是每个任务都有不同数量的参数(不同的函数接口),而worker不知道如何调用/执行给定函数的地址。

      在我的案例中使用线程池的好方法是什么,同时尽可能保持代码通用,并且能够将它从3个任务扩展到30个。

      P.S。 - 我的代码可以在任何平台上运行(Android,iOS,Linux,Windows服务器,Windows Phone等)。所以我更喜欢通用解决方案,而不是特定于操作系统或编译器的解决方案

1 个答案:

答案 0 :(得分:1)

您的错误在于您过于专注于使用功能

一种老式的方法是使基类Task具有成员函数virtual void operator()();。然后,对于任何应该是任务的内容,您创建一个Task的子类,其中包含运行所需的所有相关数据,并提供operator()的适当覆盖。

更现代的方法是创建std::function<void(void)>的任务实例,这不仅适用于上述方法,而且适用于您实际拥有该签名以及lambda的函数的情况。 (或者既然你正在进行多线程处理,可能需要像std::packaged_task<void(void)>这样的东西;我还没有真正研究过如何使用它们。

无论哪种方式,一旦您的工作线程获得对任务的引用,他们只需调用task();来执行任务。