- 线程池结构
- 任务队列结构体 保存一个回调函数指针和一个,参数指针
实现任务队列
为了多个生产者 多个消费者取东西混乱的避免要加互斥锁
- 线程池threadpool类 要实现的
- 初始化一个线城池 参数是最小数和最大数
malloc和new的区别 new要调用该类的构造函数 而mall哦草不用 直接在内存中创建 失败就抛异常new 还可以进行初始化
是否关闭线程池 默认是FALSE 如果构造失败要释放资源的 memser初始化内存 三个参数 变量名+0+多个
- 销毁线程池 析构
- 加入一个任务
- 获取忙碌线程
- 获取空闲线程
- 管理线程
- 私有属性
- 任务具体函数
- 初始化一个线城池 参数是最小数和最大数
- 任务队列结构体 保存一个回调函数指针和一个,参数指针
- 为了保护pthread线程 要求回调函数必须是有效地址 类内静态函数或普通外部函数 因为静态函数就像外部函数一样有自己的对地址,而内部函数只有类对象创建时才有
- 当这个静态函数想访问类内非静态成员时,要用this指针去访问,this指针本身又是void* 类型,完美符合,同时立马在函数内做类型转换
这个static——cast相当于C语言里的强制类型转换
- 静态类对内部函数和变量的一系列操作都需要this指针 这个pool就是this
条件阻塞 判断是不是需要销毁线程
- 工作函数其实就是不断的由线程池里的线程不断地取任务
- 首先就是先给整个线程池加上一把锁
- 判断这个任务队列是不是空的并且这个线程池没有被关闭 就把工作线程阻塞在notempty上,也就是说notempty记录了哪些工作线程被阻塞了,同时整个线程池的锁mutexpool也被解开了
- 当生产者线程开始唤醒阻塞工作线程后,线程又重新拿到了这个锁,继续向下执行
- 管理者线程判断是不是要销毁线程
- 从任务队列中取出一个任务,马上要开始工作了,busynumber++
- 解锁 任务队列 线程池
- 调用取出来的任务函数 任务执行完之前 该线程一直阻塞在这,后面就把这个GIA释放那个的资源释放
- 做日志输出
- 工作完线程busynumber-- 由于这个应该互斥访问所以加一把锁
- 线程退出
将线程ID修改为0就可以了 nullptr
- 管理者线程所要掌管的操作
- 如果当前线程不够用 同时又小于最大线程数 那就创建线程,显然这个操作要加锁
- 创建线程ID在数组里面找一个,定义回调函数为worker 现存活数+1
- 随后解锁
- 如果当前忙的线程*2 小于存活线程数 并且存活的大于最小线程数 忙线程应该包括在存活里 因为线程存在也会消耗系统资源,所以必要消毁
这时候逻辑很巧妙! 就去唤醒阻塞在条件里的工作线程,在那里它将迎来生命的终结
- 线程池添加任务函数函数 直接调用task对象的push操作就可以了
不需要再加互斥锁了,因为已经
在内部锁住了
- 获取忙碌和存活线程数 有可能修改
- 线程池整个全部析构掉的全部工作
- 阻塞管理者线程
- 唤醒所有工作线程
- 释放所有对内存 也就是任务队列 线程ID数组
- 释放所有的锁 包括大锁和条件变量
- Linux下 不会像Windows自动编译动态库,而是要在链接器里的依赖项中添加
- CTRLH 全局搜索替换
- 如何在项目中使用线程池
- 回调函数的典型应用
- Linux中的信号捕捉 Windows没有信号
- 假设我们要捕捉Linux中的某个信号,我们就把这个信号和这个信号的处理函数放到signal里 告诉捕捉了信号,你就做什么,调用的时机由signal控制 不是立即调用
- pthread类 注册事物函数 和他们的参数虽然都是void* 不是说这个事物函数去接着调用线程,而是当这个子线程被创建的时候,事物处理的时机也就来了,任务函数调用时机也就成熟了
- 所以你就能知道epoll是基于回调函数的,因为事件epollwait被触发了,事件就会被处理
- C++11新特性 绑定器和function 将一个函数包装成可调用对象
函数指针使用起来不方便,因为函数指针拿出来后函数还执行不了,需要额外添加实参对象,这时候包装成可调用对象就方便多了
- Qt是一个注射