线程池精华

1. 总体想法

  1. 线程池初始时创建任务队列、线程池,添加并启动子线程,提供接口给用户添加任务到任务队列
  2. 子线程只管从消息队列中取任务执行,将执行结果异步返回给用户
  3. 线程池销毁时等待所有子线程退出后才销毁

2. 难点

1. 如何接收用户指定的各种任务

传入线程的都是函数,而函数的不同主要是传入的参数、返回值不同,导致没法使用一个函数指针队列来接受全部类型的函数指针

  • submitTask提供用于向任务队列中添加任务的API,由用户调用,参数类型为Task智能指针
  • 使用多态 :用户使用派生类指定任务,任务队列元素为指向基类的指针,且基类中定义一个纯虚函数run(),让子线程拿到基类指针后运行
  • 但是如果用户传入的是临时对象,空间释放后再访问会导致未定义行为,所以要求用户传入shared智能指针,使得主线程出作用域后Task派生类对象依然不会被释放

2. 线程池如何添加任务并将任务队列的任务下发给线程

线程和线程池是两个对象,也就是解决,对象之间如何通信的问题

  • submitTask是生产者,用于向任务队列中添加任务
  • threadFunc是消费者,用于从任务队列中取出任务,注意这个函数是在子线程对象中调用,且需要访问线程池对象中的任务队列
  • 线程池通过将threadFunc传递给子线程,让其执行该函数(消费任务队列),从而实现任务下放(此时子线程在此函数中拥有资源线程池

3. 如何实现Any类

  • 接受任意类型:构造函数模板
  • 存储任意类型:多态 + 类模板
  • 返回指定类型:函数模板 + dynamic_cast

4. 用户如何获取任务执行后的结果(异步)

对于任务,主线程将任务到任务队列等待读取结果,子线程从任务队列中取出执行写入结果,读者-写者模型

  • 首先要有一个Result对象用于接受任意 Any结果
  • 子线程要能访问到该对象并写入结果后通知主线程读取,即在Task中包含Result对象指针
    • 指针赋值也是关键的,Task对象是用户提供并调用submitTask传入的,所以需要在这里面创建Result、将Task中的Result指针赋值为此Result,最后将该Result对象返回给用户调用地方
    • TaskResult一一对应 关系,两者有彼此的指针,注意Task周期比Result周期短,所以Result中使用shared_ptr,要注意避免循环引用
    • Result中的Task是为了将Result赋值给Task中对应指针
  • 主线程在读取结果时如果还没有产生,就需要阻塞等待,借助信号量来实现

目前未解决的问题是,Result是栈上对象,如果出作用域就直接析构,但是此时子线程正在写入,就会出现问题:解决办法是变为堆对象,且由智能指针管理,使得写入时不会被析构

5. 线程是如何归还到线程池

不存在归还,子线程一直运行,需要结束时退出循环即可,但是需要从thread_中删除自己

  • 如果是fixed模式,不需要归还,每个线程创建后就直接启动,死循环读取任务队列
  • cached需要动态调整线程池thread_,任务太多创建新线程加入线程池并启动线程,不需要多余线程时需要从线程池中去掉对应的Thread对象并关闭线程
    • 这里也存在读者-写者模型,临界资源是thread_,主线程和子线程都会对thread_进行写
    • 但是对于thread_的操作都是在taskQue_之下完成,本身就有锁,所以不需要增加多余的锁
    • 难点在于:在子线程中去删掉thread_对应的线程,thread_需要使用map,并将key传入子线程让其从线程池中删除自己

6. 线程池退出后如何结束所有子线程

线程池是主线程,这里涉及到进程间通信,读者写着模型:isPoolRunning以及threads_

  • threadPool在析构时改变isPoolRunning通知子线程,并阻塞等待子线程结束,感知到子线程全部结束
  • 子线程状态不唯一,可能正在执行任务、可能正在等待任务,但最终都会处于即将等待任务,此时可以读取到线程池要结束了,然后将自己对应的thread对象从线程池中清除

7. 优化输入输出

  1. 上述的输入是借助多态,但是得先定义类,输出是Result,但是目前看来存在多线程的问题
  2. 目标是submitTask接受函数指针和参数,返回一个结果对象,没有多线程问题
  1. submitTask接受函数,以及可变参--》可变模板
  2. 异步返回值--》packaged_task<>future<>
  3. 任务队列统一类型--》lambda中间件
  4. 函数返回类型借助传入参数确定--》auto、后置返回类型、decltype

3.从数据结构中看线程池

待补充

相关推荐
独孤九剑打醒他7 分钟前
双层Master-Worker软硬协同调度架构:从根源解决分布式数据一致性难题
后端·嵌入式硬件·硬件架构·硬件工程
浆果020739 分钟前
NanoTrack C++ — RK3588 实时目标跟踪
c++·目标跟踪·rk3588
ysa0510301 小时前
【并查集】判环
c++·笔记·算法
持力行1 小时前
C/C++ 中的 char*:它标识数组吗?为什么能用下标访问?
c语言·c++
不会c+2 小时前
02-SpringBoot配置文件
java·spring boot·后端
汉克老师3 小时前
GESP2026年6月认证C++六级( 第三部分编程题(2、满二叉树))精讲
c++·深度优先·树形dp·满二叉树·gesp六级·树形dfs
雨辰AI3 小时前
生产级实战:人大金仓 V9 标准化运维手册(日常巡检 + 监控告警 + 应急处置)
java·运维·数据库·后端
TeamDev3 小时前
JxBrowser 9.3.0 版本发布啦!
java·后端·c#·混合应用·jxbrowser·浏览器控件·异步媒体设备
踮起脚看烟花3 小时前
多人聊天室实现v2.0
c++·信息与通信
梦帮科技4 小时前
UE5 GAS 实战:用 Gameplay Ability System 搭建「赛博修真」境界与技能体系
c++·人工智能·python·ue5·c#