嵌入式八股,手撕线程池(C++)

news/2025/3/18 20:41:03/

线程池的主要目的是复用线程资源,减少线程创建和销毁的开销,同时提高程序的并发性能。

也就是说,我创建一个线程对象,他可以复用,线程池里有多个线程对象,有任务来了,我调用一个,用完了,我再放回去。

线程池优点

提高线程利用率

提高响应速度

便于统一管理线程对象

可以控制最大并发数

C++实现

#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>
#include <memory>class threadpools
{
private:/* data */std::vector<std::thread> threads;// 一个线程数组,用来加入线程,线程池那个池std::queue<std::function<void()>> task_q;//一个任务队列,用来发布任务,等待消费者来取std::mutex mtx;//一个互斥量std::condition_variable conditon;//条件变量,防止为空后继续取任务,起通知作用,管理多个线程bool stop;//控制线程池的开始与结束
public:threadpools(int threadnums);~threadpools();template <class F, class... Args>void add_task(F&& f, Args&&... args);std::atomic<int> task_count; // 添加一个任务计数器,防止主程序退出了,线程池里一个任务都没执行,我直接写公有了,不要学我};threadpools::threadpools(int threadnums):stop(false), task_count(0) {//加线程到池中到最大数目for (int i = 0; i < threadnums; i++){threads.emplace_back([this]{//加入线程,push会拷贝加入的变量,这个不会while (1){std::unique_lock<std::mutex> lock(mtx);//创建一个直接上锁conditon.wait(lock,[this]{return !this->task_q.empty() || stop;});//任务为空或线程池终止就等待结束,继续上锁,线程会卡在这里if(stop&&task_q.empty()){//一个双重检测,防止任务被其它线程取到了,导致任务列表为空从而报错,即竞态条件return;}//如果任务队列里有任务,我就取一个任务去完成std::function<void()> task(std::move(task_q.front()));task_q.pop();lock.unlock();//取到了解锁,让其它线程去取task();task_count--;}});}}threadpools::~threadpools()
{std::unique_lock<std::mutex> lock(mtx);stop = true;conditon.notify_all();//通知所有线程工作,取完所有任务for (auto& t:threads){t.join();}}//用函数模版写一个加入任务的函数
template <class F, class... Args>
void threadpools::add_task(F &&f, Args&&... args){std::function<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);std::unique_lock<std::mutex> lock(mtx);task_q.emplace(std::move(task));task_count++; // 添加任务,计数器加一conditon.notify_one();}int main(){threadpools pool(4);for (int i = 0; i < 10; i++) {std::cout << "加入任务: " << i << std::endl;pool.add_task([i] {std::this_thread::sleep_for(std::chrono::milliseconds(100));printf("任务%d已完成\n", i);});}// 等待线程池中的任务完成while (pool.task_count > 0) {std::this_thread::sleep_for(std::chrono::milliseconds(100));}return 0;
}

100行左右的CPP线程池实现,实现结果如下

我在执行add_task函数之前就输出了加入任务,按顺序加入,但输出任务实现的顺序是打乱的,符合线程池结果。

代码里还涉及到一些CPP11的新特性,比如完美转发,需要重点关注。


http://www.ppmy.cn/news/1580155.html

相关文章

Qt常用控件之表单布局QFormLayout

表单布局QFormLayout QFormLayout 是一个表单布局控件&#xff0c;属于 QGridLayout 的特殊情况&#xff0c;多用于左列提示&#xff0c;右列输入框这种 “表单” 样式。 1. 使用QFormLayout制作一个注册界面表单 addRow() 的第一个参数固定是 QLabel &#xff0c;第二个参数…

SQL Server性能优化实战

1. SQL Server性能调优的目标与意义 在处理大量数据的应用场景中(如在线购物网站、数据分析平台等),SQL Server作为企业级数据库的核心,其性能直接影响应用整体的响应时间和业务效率。以下是一些优化SQL Server性能的目的: 提高查询执行速度。减少等待时间,提升系统吞吐…

鸿蒙的 Stage 模型

鸿蒙的 Stage 模型 在鸿蒙 Next 开发中&#xff0c;Stage 模型是应用开发的核心架构之一&#xff0c;它为开发者提供了一种高效、灵活的方式来构建分布式应用。本文将详细介绍鸿蒙 Stage 模型的基本概念、应用配置文件的使用、UIAbility 组件的介绍以及如何通过 Stage 模型开发…

鸿蒙路由 HMRouter 配置及使用 三 全局拦截器使用

1、前期准备 简单封装一个用户首选项的工具类 import { preferences } from "kit.ArkData";// 用户首选项方法封装 export class Preferences {private myPreferences: preferences.Preferences | null null;// 初始化init(context: Context, options: preference…

大型语言模型(LLM):解码人工智能的“语言基因“

文章目录 引言&#xff1a;与文字共舞的智能革命一、LLM本质解析&#xff1a;文字的"DNA测序"1. 语言模型的进化史2. LLM的"生物结构" 二、LLM训练全揭秘&#xff1a;打造语言天才的"九年义务教育"1. 数据盛宴&#xff1a;吞下整个互联网2. 核心…

c++入门基本知识掌握

学习要求&#xff1a;1.关键词 &#xff08;先大致看看哪些学过 不让你背下来 就让你看看&#xff09;2.命名空间 3.输入输出&#xff08;cin&cout&#xff09;4. 缺省参数 5.函数重载 6. 引用 7. 内联函数 8. auto关键字 还有for-each&#xff08;新用法&#xff09; 9…

搭建opensbi+kernel+rootfs及基本设备驱动开发流程

目录 一.编译qemu 运行opensbikernelrootfs 1.编译qemu-9.1.1 2.安装riscv64编译器 3. 编译opensbi 4.编译kernel 5.编译rootfs 设备驱动开发流程 1.安装 RISC-V 交叉编译工具链 2.驱动开发准备 3.编写简易中断控制器驱动&#xff08;PLIC&#xff09;​ 4.配置内核…

Python基于Django和协同过滤算法实现电影推荐系统功能丰富版

说明&#xff1a;这是一个系统实战项目&#xff0c;如需项目代码可以直接到文章最后关注获取。 项目背景 随着互联网的普及和数字娱乐内容的爆发式增长&#xff0c;用户在海量的电影资源中找到自己感兴趣的影片变得愈发困难。为了提升用户体验并增加用户粘性&#xff0c;我们…