C++,当每个工作线程都必须执行几个不同的任务时,如何为任务实现线程池
C++, How to implement Thread pool for tasks when each worker thread has to do few different tasks
我正在分析一个视频流。对于每个新图像(帧),我依次执行以下3项任务:
- 缩小图像大小
- 检测人脸
- 跟踪图像中最重要的4个面
为了在4-pu机器上加快速度,我使用了4个工作线程。按照以下方式
- 主进程得到一个图像。创建4个工作线程,将图像拆分为4个四分之一,每个工作线程重新调整其1/4的图像像素大小。主进程等待线程完成并将四分之一装配到最终图像
- 主流程为人脸检测创建了4名新员工。我检测到4种类型的脸(雄性、雌性、婴儿、狗)。每个工作线程负责一种类型。主进程等待工人完成并组装结果(所有现有面的列表)
- 主流程为人脸跟踪创建了4名新员工。选择4个最重要的面,并且每个工人跟踪1个面。主进程等待完成
我的实现的问题是我没有线程池。在每个视频帧上(大约每秒30次),主进程上升并杀死12名工人(4名工人x 3项不同的任务)。所以在线程管理上浪费了很多时间。目前,我使用_beginthreadex()
方法为特定任务提供工作线程午餐
所需解决方案:我只想创建一次4个工作线程(每个工作线程能够执行所有3个不同的任务)。这些工作人员将存在于整个视频处理过程中。在每个视频帧上,主进程都会将图像重新调整大小的任务交给工作人员,然后进行检测和跟踪。
一个丑陋的实现是每个工作线程都是一个大函数,实现了所有3个任务。主进程只是告诉每个工人要执行哪个任务(工人有一个"switch"语句来选择请求的任务)。这是一个丑陋的解决方案,因为在未来,当我将有30个不同的任务而不是3个时,工人的代码将变得巨大。此外,这个解决方案违反了封装规则,因为它要求所有任务都位于同一个函数中+对于每个新任务,我需要更改工作的代码
一个干净的实现是主进程为每个工作进程提供一个指向函数(要执行的任务)和一些参数的指针。因此,我可以很容易地在视频处理管道中添加新任务,而无需更改工作者的代码,因为工作者的代码是通用的(执行指向函数的指针并等待具有新指针的请求到达)但这里的问题是,每个任务都有不同数量的参数(不同的函数接口),工作人员不知道如何调用/执行给定函数的地址。
在我的情况下,使用线程池的好方法是什么,同时尽可能保持代码的通用性,并能够将其从3个任务扩展到30个任务。
附言-我的代码可以在任何平台上运行(Android、iOS、linux、windows服务器、windows手机等)。因此,我更喜欢通用解决方案,而不是特定于操作系统或编译器的解决方案
您的错误是过于专注于使用函数。
一种老式的方法是使用具有成员函数virtual void operator()();
的基类Task
。然后,对于任何应该是任务的东西,您创建Task
的子类,该子类包含运行所需的所有相关数据,并提供operator()
的适当覆盖。
一种更现代的方法是使任务成为std::function<void(void)>
的实例,这不仅适用于上述方法,而且适用于那些实际具有该签名和lambdas的函数的情况。(或者,由于您正在进行多线程处理,可能需要std::packaged_task<void(void)>
之类的东西;我还没有真正研究过这些东西是如何使用的)
无论哪种方式,一旦您的工作线程获得了对任务的引用,它们只需调用task();
来执行该任务。
- 如何创建线程序列以按照启动顺序执行任务?
- C++一个线程如何正确通信其任务已完成?
- 对于同一任务,线程的等待时间在 0 到 30000 微秒之间系统地切换
- 在iOS设备上执行并发任务时如何设置正确的线程数?
- 如何从父线程中提取 pthread 的任务 id(tid)
- 根据硬件并发性将任务平均划分为线程
- C++生产者使用者中,同一使用者线程会抓取所有任务
- 正在执行 omp 任务的线程数
- 您可以在 OpenMP 中将特定线程 ID 分组到唯一的任务组中吗?
- 是boost :: asio :: thread_pool线程在多个线程上发布任务时的安全性
- asio::strand 上的任务在单个线程上运行
- 如何在C++中创建高效的多线程任务计划程序
- 如何在多个线程上正确分发任务
- 在多线程中调度任务
- Poco任务管理器/Boost线程混合和匹配
- 将执行从一个线程移动到另一个线程,以实现任务并行性并在将来调用
- 使用C 多任务.线程或不同的设计
- 如何处理任务,同时剩余的线程完成工作
- 提升:偶尔同步任务的ASIO线程池实现
- PPL任务何时在UI线程上执行