c++实现线程池(真实入门!)

c++11线程池实现 咳咳。c++11 加入了线程库,从此告别了标准库不支持并发的历史。然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池、信号量等。线程池(thread pool)这个东西,在面试上多次被问到,一般的回答都是:“管理一个任务队列,一个线程队列,然后每次取一个任务分配给一个线程去做,循环往复。” 貌似没有问题吧。但是写起程序来的时候就出问题了。 阅读详情

10分钟学会用C++编写一个简单的线程池(使用windows.h头文件)

前言

这是我们操作系统专业课的一次编程作业,作为菜鸡的我搜索了大量的线程池博客,但不是代 码太秀,比较难懂,就是实现的线程池功能太过强大,不适合入门,或是讲解重点并没解决我 的问题,而不同博客使用的头文件又不同;很难有只需一篇就能让菜鸡搞懂的博客。

所以我打算以我从零开始理解的角度完成这篇 实验报告 博客,能让最菜的菜鸡也能看懂并手 动实现一个最简单的线程池。

但要做到这一点,需要有一点点前提条件:

  1. 只需要有简单的c++面向对象编程的能力。
  2. 会使用win自带的 “windows.h” 头文件进行多线程编程。
  3. 对线程有基本的理解。

而我们最终能得到的线程池拥有的功能有:

  1. 实现线程池最基本的功能能:线程重复利用,少量线程完成大量工作(线程数<任务 数)。
  2. 可自己设计任务函数,而不是简单的模拟。(同GreatThread() 传入参数的方法类似)
  3. 可调节线程池的线程数,空闲线程等待时间等。
  4. 可随时添加新任务,添加结束后可调用等待函数等待线程完成所有工作。
  5. 不能直接接收返回值,但返回值可利用传入的参数指针传回。

基本概念

  1. 为啥要有线程池
    一般的多线程编程,往往是一个线程对应一个 ‘任务’ 。但由于线程的建立于销毁也会造成一部分开销,所以当任务过多的时候,若还是一个任务对应一个线程,线程的反复建立与销毁,会造成大量的的资源浪费。

  2. 什么是任务
    这一点是大部分博客都没有提及的,以我的理解,这里的任务所指的是你打算在线程函数里面完成的工作,比如打印 “hello word” 或者做一些计算之类的。
    而大部分任务往往都能封装进一个函数,所以这里的任务往往就是指一个有明确目的函数(相同函数传入不同参数也能看成不同的任务)

  3. 什么是线程池
    如果我们重复利用几个线程,去完成比线程数更多的任务,那不就避免了线程建立和销毁造成的开销么。
    一句话说:线程池就是一种利用少量线程解决大量任务(线程数 < 任务数)的工具。
    而高级的线程池会从线程的数量,线程的活跃时间,任务的存取策略等角度进行优化,以达到更高效目的。

  4. 如何实现
    我们可以把所有的任务放在一个队列内,并创建一定数量的线程。线程空闲时,可以自动从任务队列中取出任务,任务完成后,又进入空闲,并尝试取出下一个任务。而这,就是最简单的线程池了。

代码实现

“任务”的封装

综上所述,我们需要实现的任务需要有这样的特性:

  1. 创建任务和运行任务可以不同步(不同于简单的调用函数)。
  2. 因为要放入队列,所以需要有具体的数据结构。
  3. 需要固定任务的格式(总不能让用户随便传入啥类型的函数都行吧,得规范一下)

解决方案:

首先,统一任务函数的格式:”参数为 void 指针,返回值为void(没有返回值)“。

这样的话,利用void指针可以指向任何数据的特性,任务函数可以传入任意类型的参数了,也可以利用指针传回返回值。

// 声明fp_return_void类型
typedef void(*fp_return_void)(void *paramter);

见:函数指针的用法

其次,将函数指针和参数指针分开来, 并进行封装,想运行函数的时候,直接调用函数指针并把参数传入即可(见run()成员函数)

class Task
{
   
   
private:
	// 函数指针和参数指针
	fp_return_void fp;
	void *paramter;

	// 构造函数,需传入函数指针和参数指针
	Task(fp_return_void fp, void *param) :
		fp(fp), paramter(param) {
   
   }

	// 运行任务
	void run()
	{
   
   
		fp(paramter);
	}

public:// 声明为线程池的友元类
	friend class KyThreadPool;

};

Task使用方法:

// 声明自己的任务函数
void FuncName(void *lpParamter)
{
   
   
	int *pmd = (int *)lpParamter;// 假设需要传入int指针,(int *)表示强制类型转换,相当于告诉函数void指针指向的是int类型。
	cout << "task " << pmd[0] << " is working!\n";
}

//声明参数
int x = 1;
int *p = &x;

// 声明一个任务
Task onetask(FuncName, p); 
onetask.run(); // 运行任务

线程池框架构建

根据线程池的概念,线程池的主体必要两个东西:

  1. 线程函数,有任务的时候做任务,没任务的时候等任务,等久了就自动结束。
  2. 任务队列,用于存放任务,供线程函数提取任务用。(见:STL队列用法)

还需要一些池子的参数:

  1. 核心线程数/最大线程数(为了简便,假设核心线程数 = 最大线程数)
  2. 空闲线程等待时间,空闲线程也会占用cpu,所以不能让空闲线程活太久
  3. 现存线程数量,活跃线程数量,线程结束标志等,用于管理线程

以及几个供给用户使用的函数:

  1. 等待线程池函数,线程停止接收任务,等待剩余线程完成任务。
  2. 重启线程池函数,使线程池重新工作
  3. 添加任务函数,用于增加一个任务到队列中。

C++—线程池(附源代码) std::atomic 提供了原子操作,适用于需要在多线程环境中进行无锁操作的场景。std::atomic_flag 用于实现低级别的锁机制,如自旋锁。了解内存序是使用原子操作时的一个重要方面,它帮助你控制操作的顺序和可见性,从而确保程序的正确性和效率。 阅读详情

相关推荐

【C语言和C++】实现线程池

线程,线程池

m0_64560763的博客 3148

C++ 线程池实现原理

背景 多线程编程是C++开发者的一个基本功, 但是很多开发者都是直接使用公司给包装好的线程池库, 没有去了解具体实现,有些实现也都因为高度优化而写得讳莫如深,让初学者看得吃力。 所以写这篇文章主要是想以非常简单的方式讲讲实现原理, 希望初学者看完之后不是觉得「不明觉厉」,而是觉得「原来如此」。 面朝代码 首先先来一段超级简单(注释丰富)的代码展示多线程编程的经典写法。 注: 该段代码和完...

3187

C++新特性实现高效线程池,程序性能瞬间提升!

本文深入探讨了如何利用C++新特性实现高效线程池,提升程序性能。首先介绍了C++11和C++14中提供的新特性,如std::thread、std::future、std::function等,并解释了它们如何用于线程池的实现。然后详细介绍了线程池的设计原理和实现过程,包括任务队列的管理、线程的管理以及线程池的调度策略。通过充分利用C++新特性,使得线程池在高并发场景下表现出色,大大提升了程序的性能和响应速度。

Lion_Long的博客 4245

AWS-解析mysql binlog同步数据方案

虽然是公有云的鼻祖,AWS在某些产品的实现却太不给力;可能是习惯了阿里云喂到嘴边的感觉,AWS很多方案需要自己折腾,蛋疼!比如这里要讲的mysql数据同步方案。 阿里云产品DTS,点几下就OK了,AWS,只能通过插件安装、配置、调试、蹚坑……,具体就是用msk的debezium插件连接器。没见识过的一脸懵逼,下面说下配置步骤和一些注意的坑。

sdmei 1406

FreeSurfer预处理命令

比如将/source/kernel.tgz解压到 /source/linux-2.6.29 目录 tar zxvf /source/kernel.tgz -C /source/ linux-2.6.29 tar zxvf /home/tj/application/freesurfer/subjects/mindboggle/OASIS-TRT-20-1.tar.gz -C /home/tj/application/freesurfer/subjects (1)lh.thickness mri_surf2su

Dream19961996的博客 1506

逆向拆解dy接口a_bogus 1.0.1.19版本核心算法(纯算版)第二部分

本文深入解析了dy接口a_bogus 1.0.1.19版本的核心算法,重点介绍了逆向分析的基础方法论、魔改Base64编码识别与还原、随机数生成与位运算解析等关键技术。通过详细的代码示例和实用技巧,帮助开发者掌握逆向工程中的关键步骤,特别是针对a_bogus参数的生成逻辑和混淆处理。

weixin_29288313的博客 407

从 SM30 到 Fiori:在 SAP BTP ABAP Environment 里创建 Business Configuration 配置维护对象的完整路径

摘要 在SAP BTP的ABAP环境中,传统SAP GUI和SM30配置方式被Business Configuration (BC)替代。BC通过Fiori应用维护配置,支持传输和权限控制。配置表需满足可维护性条件,如允许数据维护、包含技术字段等。通过ADT生成Maintenance Object和Transport Object,实现配置发布与治理。权限管理需创建IAM App和Business Catalog,确保配置可维护。BC在云端延续了可控、可追溯、可发布的治理原则。 (字数:150)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 241

AI Agent Harness实时监控大屏搭建实战

本文将以目前主流的AI Agent管控框架Harness为基础,结合React、ECharts、WebSocket技术,手把手带你搭建一套完整的实时监控大屏,覆盖全局概览、状态分布、工具调用统计、异常告警、实时日志等核心功能,不需要复杂的底层开发,复制代码就能快速跑通。本文我们从需求出发,先梳理了AI Agent的核心监控指标,然后搭建了监控大屏的静态布局,逐个实现了各个图表,对接了Harness的实时数据源,最后加了交互和告警功能,完整走了一遍监控大屏从设计到落地的全流程。

大数据洞察的博客 174

Android 自动亮度

/则需要从BrightnessConfigure类中读取两个数组源:config_autoBrightnessLevels和config_autoBrightnessDisplayValuesNits。) 或知道其在DisplayPowerController()构造的时候初始化的。曲线设置好了,就应该扔代码里跑起来,模型建起来了,这个过程是咋样的呢?//它将负责曲线的创建,自动背光值的计算等。通过搜索配置关键词(

Android 1485

【定制功能】LVGL 页面管理

页面管理的主要针对实际复杂的UI项目的。支持多页面管理,包含页面跳转和返回(主要是方便项目功能管理)支持后台页面自动销毁、前台页面自动创建(主要是节约资源使用)支持语言切换逻辑(页面重建功能)支持主题切换逻辑支持页面切换动画效果首先,页面管理是针对act_src图层来讲的。仅在screens数组中供act_src切换的对象树才会被此页面管理功能所管理。这意味着,如果top_layer或者sys_layer图层上,有页面需要重建时,需要特殊处理(实际项目中top_layer或者。

Bigan(安)的博客 5751

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

上一篇: Dijkstra算法为什么不能用于负权图
下一篇: C++多线程编程(真实入门!)
Korpse
博客等级 码龄9年 115粉丝 25原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值