实现一个简单的linux线程池

c++ 实现的线程池(linux环境下) c++ 实现的线程池(linux环境下),大家一块学习,共同进步。 立即下载

线程池:简单地说,线程池 就是预先创建好一批线程,方便、快速地处理收到的业务。比起传统的到来一个任务,即时创建一个线程来处理,节省了线程的创建和回收的开销,响应更快,效率更高。

 

在linux中,使用的是posix线程库,首先介绍几个常用的函数:

1 线程的创建和取消函数

pthread_create

创建线程

pthread_join

合并线程

pthread_cancel

取消线程

2 线程同步函数

pthread_mutex_lock

pthread_mutex_unlock

pthread_cond_signal

pthread_cond_wait

 

关于函数的详细说明,参考man手册

 

线程池的实现:

线程池的实现主要分为三部分,线程的创建、添加任务到线程池中、工作线程从任务队列中取出任务进行处理。

主要有两个类来实现,CTask,CThreadPool

/**
执行任务的类,设置任务数据并执行
**/
class CTask
{
protected:
 string m_strTaskName;  //任务的名称
 void* m_ptrData;       //要执行的任务的具体数据
public:
 CTask(){}
 CTask(string taskName)
 {
  this->m_strTaskName = taskName;
  m_ptrData = NULL;
 }
 virtual int Run()= 0;
 void SetData(void* data);    //设置任务数据
};

 

任务类是个虚类,所有的任务要从CTask类中继承 ,实现run接口,run接口中需要实现的就是具体解析任务的逻辑。m_ptrData是指向任务数据的指针,可以是简单数据类型,也可以是自定义的复杂数据类型。

 

线程池类

/**
线程池
**/
class CThreadPool
{
private:
 vector<CTask*> m_vecTaskList;         //任务列表
 int m_iThreadNum;                            //线程池中启动的线程数          
 static vector<pthread_t> m_vecIdleThread;   //当前空闲的线程集合
 static vector<pthread_t> m_vecBusyThread;   //当前正在执行的线程集合
 static pthread_mutex_t m_pthreadMutex;    //线程同步锁
 static pthread_cond_t m_pthreadCond;    //线程同步的条件变量
protected:
 static void* ThreadFunc(void * threadData); //新线程的线程函数
 static int MoveToIdle(pthread_t tid);   //线程执行结束后,把自己放入到空闲线程中
 static int MoveToBusy(pthread_t tid);   //移入到忙碌线程中去
 int Create();          //创建所有的线程
public:
 CThreadPool(int threadNum);
 int AddTask(CTask *task);      //把任务添加到线程池中
 int StopAll();
};

当线程池对象创建后,启动一批线程,并把所有的线程放入空闲列表中,当有任务到达时,某一个线程取出任务并进行处理。

线程之间的同步用线程锁和条件变量。

这个类的对外接口有两个:

AddTask函数把任务添加到线程池的任务列表中,并通知线程进行处理。当任务到到时,把任务放入m_vecTaskList任务列表中,并用pthread_cond_signal唤醒一个线程进行处理。

StopAll函数停止所有的线程

 

 

 

************************************************

代码:

××××××××××××××××××××CThread.h

 

#ifndef __CTHREAD
#define __CTHREAD
#include <vector>
#include <string>
#include <pthread.h>

using namespace std;

/**
执行任务的类,设置任务数据并执行
**/
class CTask
{
protected:
 string m_strTaskName;  //任务的名称
 void* m_ptrData;       //要执行的任务的具体数据
public:
 CTask(){}
 CTask(string taskName)
 {
  this->m_strTaskName = taskName;
  m_ptrData = NULL;
 }
 virtual int Run()= 0;
 void SetData(void* data);    //设置任务数据
};

/**
线程池
**/
class CThreadPool
{
private:
 vector<CTask*> m_vecTaskList;         //任务列表
 int m_iThreadNum;                            //线程池中启动的线程数          
 static vector<pthread_t> m_vecIdleThread;   //当前空闲的线程集合
 static vector<pthread_t> m_vecBusyThread;   //当前正在执行的线程集合
 static pthread_mutex_t m_pthreadMutex;    //线程同步锁
 static pthread_cond_t m_pthreadCond;    //线程同步的条件变量
protected:
 static void* ThreadFunc(void * threadData); //新线程的线程函数
 static int MoveToIdle(pthread_t tid);   //线程执行结束后,把自己放入到空闲线程中
 static int MoveToBusy(pthread_t tid);   //移入到忙碌线程中去
 int Create();          //创建所有的线程
public:
 CThreadPool(int threadNum);
 int AddTask(CTask *task);      //把任务添加到线程池中
 int StopAll();
};

#endif

 

 

 

类的实现为:

××××××××××××××××××××CThread.cpp

 

#include "CThread.h"
#include <string>
#include <iostream>

using namespace std;

void CTask::SetData(void * data)
{
 m_ptrData = data;
}

vector<pthread_t> CThreadPool::m_vecBusyThread;
vector<pthread_t> CThreadPool::m_vecIdleThread;
pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;

CThreadPool::CThreadPool(int threadNum)
{
 this->m_iThreadNum = threadNum;
 Create();
}
int CThreadPool::MoveToIdle(pthread_t tid)
{
 vector<pthread_t>::iterator busyIter = m_vecBusyThread.begin();
 while(busyIter != m_vecBusyThread.end())
 {
  if(tid == *busyIter)
  {
   break;
  }
  busyIter++;
 }
 m_vecBusyThread.erase(busyIter);
 m_vecIdleThread.push_back(tid);
 return 0;
}

int CThreadPool::MoveToBusy(pthread_t tid)
{
 vector<pthread_t>::iterator idleIter = m_vecIdleThread.begin();
 while(idleIter != m_vecIdleThread.end())
 {
  if(tid == *idleIter)
  {
   break;
  }
  idleIter++;
 }
 m_vecIdleThread.erase(idleIter);
 m_vecBusyThread.push_back(tid);
 return 0;
}
void* CThreadPool::ThreadFunc(void * threadData)
{
 pthread_t tid = pthread_self();
 while(1)
 {
  pthread_mutex_lock(&m_pthreadMutex);
  pthread_cond_wait(&m_pthreadCond,&m_pthreadMutex);
  cout << "tid:" << tid << " run" << endl;
  //get task
  vector<CTask*>* taskList = (vector<CTask*>*)threadData;
  vector<CTask*>::iterator iter = taskList->begin();
  while(iter != taskList->end())
  {
   
   MoveToBusy(tid);
   break;
  }
  CTask* task = *iter;
  taskList->erase(iter);
  pthread_mutex_unlock(&m_pthreadMutex);
  cout << "idel thread number:" << CThreadPool::m_vecIdleThread.size() << endl;
  cout << "busy thread number:" << CThreadPool::m_vecBusyThread.size() << endl;
  //cout << "task to be run:" << taskList->size() << endl;
  task->Run();
  
  //cout << "CThread::thread work" << endl;
  cout << "tid:" << tid << " idle" << endl;
  
 }
 return (void*)0;
}

int CThreadPool::AddTask(CTask *task)
{
 this->m_vecTaskList.push_back(task);
 pthread_cond_signal(&m_pthreadCond);
 return 0;
}
int CThreadPool::Create()
{
 for(int i = 0; i < m_iThreadNum;i++)
 {
  pthread_t tid = 0;
  pthread_create(&tid,NULL,ThreadFunc,&m_vecTaskList);
  m_vecIdleThread.push_back(tid);
 }
 return 0;
}

int CThreadPool::StopAll()
{
 vector<pthread_t>::iterator iter = m_vecIdleThread.begin();
 while(iter != m_vecIdleThread.end())
 {
  pthread_cancel(*iter);
  pthread_join(*iter,NULL);
  iter++;
 }

 iter = m_vecBusyThread.begin();
 while(iter != m_vecBusyThread.end())
 {
  pthread_cancel(*iter);
  pthread_join(*iter,NULL);
  iter++;
 }
 
 return 0;
}

简单示例:

××××××××test.cpp

#include "CThread.h"
#include <iostream>

using namespace std;

class CWorkTask: public CTask
{
public:
 CWorkTask()
 {}
 int Run()
 {
  cout << (char*)this->m_ptrData << endl;
  sleep(10);
  return 0;
 }
};
int main()
{
 CWorkTask taskObj;
 char szTmp[] = "this is the first thread running,haha success";
 taskObj.SetData((void*)szTmp);
 CThreadPool threadPool(10);
 for(int i = 0;i < 11;i++)
 {
  threadPool.AddTask(&taskObj);
 }
 while(1)
 {
  sleep(120);
 }
 return 0;
}

论文选题难?7种AI加持的万能选题法(全专业通用+工具实测) AI时代学术选题新范式:7大智能方法破解研究痛点 传统选题方法面临范围失控、资料难寻、创新不足三大痛点,本文提出AI赋能的7种选题方法论: 1.现象+群体法:自动抓取热点与人群特征 2.理论+场景法:经典理论与新兴场景匹配 3.技术+问题法:前沿技术与领域痛点结合 4.对比+变量法:时空维度与变量关系分析 5.热点+理论法:事件传播与理论深挖融合 6.微调+变量法:已有选题变量置换创新 7.AI全流程法:关键要素智能迭代生成 同时警示AI使用的伦理边界,需规避虚构文献、伪造数据等风险,并提供针对本科生、研究 阅读详情

相关推荐

java对接海康实现页面实时播放和回放

前言:之前已经写过一篇关于视频的文章,因为觉得有很多优化的地方,也谢谢同行们加我微信跟我提了一些需求和意见,所以在过年的假期重新写了一个比较能扩张的版本。 上一个版本的连接:https://blog.youkuaiyun.com/weixin_45848110/article/details/119363602 与之前的版本不同之处: 1.不需要安装ffmpeg 2.不需要安装nginx 3.直接运行jar即可 4.之前是完全脱离海康sdk,回放的录像是保存到本地服务,现在是直接在海康硬盘录像机获取录像回放 5.实时播

weixin_45848110的博客 1万+

Linux —— 线程池

一、什么是线程池二、线程池的优点三、线程池的应用四、实现一个简单的线程池五、单例模式1. 饿汉实现方式2. 懒汉实现方式3. 单例模式实现线程池(懒汉方式)六、其他常见的各种锁

M的博客 5933

如何解决ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE.

解决ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE

2745

Singleton单例模式

Singleton单例模式 单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。如,IO处理,数据库操作等,这些对象都要占用重要的系统资源。又比如,在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通...

《好好先生》专栏 444

HCIA重点知识

华为认证ICT工程师,是华为认证体系中用于标识个人能力在某一技术领域达到工程师级别的证明,表示通过认证的人员具备安装、配置、运行 ICT 设备,并进行基础故障排除的能力。抽象语言 -----> 编码 -----> 二进制 -----> 电信号 -----> 处理电信号信号的转换标准:协议,是一种允许电子设备相互交流的一系列标准的规则。即开放系统参考模型OSI/RM,简称“OSI”。OSI参考模型将计算机网络分为七个层次,自上而下依次为:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。1、应用层:

Awen0201的博客 2544

Dify+firecrawl:一个超好用的网页转Markdown API,打造你的第一个能检索爬虫RAG知识库的聊天机器人

Firecrawl是一个超简单的API服务——你扔给它一个URL,它就能把整个网站(包括子页面!)的内容自动抓下来,并且转换成干净、易读的Markdown格式。不用配置网站的站点地图,不用写爬虫规则,API调一下,数据直接到手。接下来我们一起本地部署吧!

2501_91673550的博客 2992

【Linux】线程池

Linux线程池

qq_53893431的博客 1959

万物皆可GAN ---普通GAN, pix2pix, CycleGAN和pix2pixHD的比较以及演变过程

普通GAN, pix2pix, CycleGAN和pix2pixHD的原理、比较以及演变过程

m0_61985580的博客 3726

< Linux > 多线程(线程池)

目录 1、线程池的概念 2、线程池的使用场景 3、线程池的代码实现

bit_zyx的博客 1135

PWN-shellcode

构造一段shellcode的作用就是为了在缓冲区溢出时将shellcode的地址覆盖掉正常的返回地址。 题目: 1Ch=16+12=28,+esp=32:偏移量是32 能溢出:100-0x1c-4=68字节 C伪代码: 理论基础 函数返回步骤 : 保存返回值:函数返回值保存在EAX寄存器 弹出当前栈帧,恢复上一个栈帧 a) ESP + 当前栈帧大小:堆栈平衡基础上,降低栈顶,回收当前栈帧空间...

MuMuLee_的博客 2086

uniapp [微信小程序] - 实现语音播报功能+实时收款播报,使用同声传译插件做文字转语音播报类似微信/支付宝收款播报小程序语音识别和朗读,手机提醒播放自定义收款语音信息(音频+收款金额+文案)

uniapp-实现语音播报功能,实时收款播报,uni-app/vue 文字转语音朗读(附小程序语音识别和朗读)uniapp小程序使用文字转语音播报类似支付宝收款播报小程序语音识别和朗读)IOS苹果手机播报没有声音,生成语音并播放,微信小程序接入官方wechatSi(微信同声传译)uniapp小程序使用文字转语音播报类似支付宝收款播报,uni-app 小程序端实现文字语音播报,uniAPP文本转语音,uniapp 文字转语音文字播报,手机静音播放没声音,收款方提示音 文字转语音朗读 同声传译,uniapp小程

🏆 前端领域优质创作者 3795

【转载】实现一个简单的linux线程池

原网址:http://blog.youkuaiyun.com/zhsp1029/archive/2009/01/17/3819502.aspx   线程池:简单地说,线程池 就是预先创建好一批线程,方便、快速地处理收到的业务。比起传统的到来一个任务,即时创建一个线程来处理,节省了线程的创建和回收的开销,响应更快,效率更高。在linux中,使用的是posix线程库,首先介绍几个常用的函数

揭谛揭谛波罗揭谛波罗僧揭谛菩提萨婆诃~~~~ 372

【目标检测】基于yolov5的铝型材表面缺陷检测(附代码和数据集,Ubuntu或者Linux系统均可运行)

【目标检测】基于yolov5的铝型材表面缺陷检测(附代码和数据集,Ubuntu或者Linux系统均可运行)

学无止境、积少成多、厚积薄发 2171

【Linux】 实现一个简单的线程池

线程池的概念 “池”的概念大家应该不陌生,线程池顾名思义就是存放线程的“池子”。 它是一种线程的使用模式。我们发现如果线程过多会带来调度的开销,进而影响缓存的局部性和整体性能。 而线程池维护着一定数量的线程,等待监督管理者分配可并发执行的任务,从而避免了在处理短时间任务时创建和销毁线程的代价。所以线程池不仅能够保证内核的充分利用,还能防止线程的过分调度。 总结:线程池很好的解决了在处理任务时的效...

ly_6699的博客 324

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Linux下一个简单线程池实现的源码注释

这里阅读了一份用C实现的

大冰的小屋 939

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Linux C 实现一个简单的线程池

线程池的定义 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一...

aiduan6474的博客 76

Linux:实现一个简单的线程池

线程池 一、定义:线程池是一种线程使用模式。 二、目的:线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 三、应用场景: 需要大量的线程来...

ENSHADOWER的博客 423

线程池 c linux 编程,Linux C 实现一个简单的线程池

线程池的定义线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但...

weixin_35679132的博客 114

【Linux】基于线程池简单实现一个计算器

基于线程池简单实现一个计算器 #include <iostream> #include <queue> #include <pthread.h> #include <unistd.h> #include <time.h> #include <stdlib.h> using namespace std; int cal(i...

流云 351

一个linux下c线程池的实现,Linux C线程池简单实现实例

Linux C线程池三个文件1 tpool.htypedef struct tpool_work {void (*routine)(void *);void *arg;struct tpool_work *next;} tpool_work_t;typedef struct tpool {/* pool characteristics */int nu...

weixin_36002475的博客 188

linux下用c语言实现一个简单的线程池

首先大家思考一个问题:为什么需要内存池? 我们知道应用程序创建一个对象,然后销毁对象是很耗费资源的。创建线程,销毁线程,也是如此。因此,我们就预先生成一些线程,等到我们使用的时候在进行调度,于是,一些"池化资源"技术就这样的产生了。 1 线程池优点 下面使用网上资源验证线程池如何提高服务器性能的。 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单

hj605635529的博客 4169

Linux C++ 一个线程池的简单实现

这是对pthread线程的一个简单应用 1.      实现了线程池的概念,线程可以重复使用。 2.      对信号量,互斥锁等进行封装,业务处理函数中只需写和业务相关的代码。 3.      移植性好。如果想把这个线程池代码应用到自己的实现中去,只要写自己的业务处理函数和改写工作队列数据的处理方法就可以了。   Sample代码主要包括一个主程序和两个线程实现类 Thread

回忆丶那些年的专栏 580

Linux C++ 一个线程池的简单实现(附代码)

这是对pthread线程的一个简单应用 1. 实现了线程池的概念,线程可以重复使用。 2. 对信号量,互斥锁等进行封装,业务处理函数中只需写和业务相关的代码。 3. 移植性好。如果想把这个线程池代码应用到自己的实现中去,只要写自己的业务处理函数和改写工作队列数据的处理方法就可以了。 Sample代码主要包括一个主程序和两个线程实现类 ThreadTest.cpp:主程序 CT

晴天的专栏 1272
上一篇: 进程间通信---信号量
下一篇: 什么时候需要定义拷贝构造函数
zhsp1029
博客等级 码龄21年 115粉丝 89原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值