C++线程池总结
本文采用pthread实现线程池,有以下几个类。
CTask:任务抽象类,主要提供接口,供子类实现。
CMyTask:继承CTask实现接口
CThreadPool:线程池类,用于管理线程。
信号量:主要有两类,一个是条件信号量,主要是用于,主线程告诉子线程有新的任务到来,所以当任务队列里面为空的时候,子线程处于阻塞状态。还有一个信号量,是用于控制多个子线程对任务队列的访问的,同时只有一个子线程对任务队列进行访问。
线程池的实现:首先由线程池对象创建几个线程,创建好后调用相应的回调函数,然后子线程因为任务队列为空进入阻塞状态。
采用消费者-生产者模型,主线程负责添加任务,子线程负责获取任务,执行操作。子线程,没有任务就阻塞,主线程,有任务就激活子线程。
任务抽象类
class CTask
{
protected:
string m_strTaskName; /** 任务的名称 */
void* m_ptrData; /** 要执行的任务的具体数据 */
public:
CTask(){}
CTask(string taskName)
{
m_strTaskName = taskName;
m_ptrData = NULL;
}
// 纯虚函数,相当于定义接口
virtual int Run()= 0;
// 因为向线程传参是采用void\* 类型,若果有多个变量,可以考虑用类或者结构体
void SetData(void* data); /** 设置任务数据 */
public:
virtual ~CTask(){}
};
具体任务类
继承抽象类,实现接口
class CMyTask: public CTask
{
public:
CMyTask(){}
int Run()
{
// 这里进行相关的操作
printf("%s\n", (char*)this->m_ptrData);
sleep(10);
return 0;
}
};
线程池类定义
/**
* 线程池管理类的实现
*/
class CThreadPool
{
private:
static vector<CTask*> m_vecTaskList; /** 任务列表 */
static bool shutdown; /** 线程退出标志 */
int m_iThreadNum; /** 线程池中启动的线程数 */
pthread_t *pthread_id; /** 线程id,用于控制线程*/
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 = 10); /** 默认创建十个子线程 */
int AddTask(CTask *task); /** 把任务添加到任务队列中 */
int StopAll(); /** 使线程池中的线程退出 */
int getTaskSize(); /** 获取当前任务队列中的任务数 */
};
线程池类实现
#include "Thread.h"
#include <iostream>
void CTask::SetData(void * data)
{
m_ptrData = data;
}
vector<CTask*> CThreadPool::m_vecTaskList; //任务列表
bool CThreadPool::shutdown = false;
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;
cout << "I will create " << threadNum << " threads" << endl;
Create();
}
/**
* 线程回调函数
*/
void* CThreadPool::ThreadFunc(void* threadData)
{
pthread_t tid = pthread_self();
while (1)
{
// 因为要访问任务队列,所以要加同步锁
pthread_mutex_lock(&m_pthreadMutex);
while (m_vecTaskList.size() == 0 && !shutdown)
{
// 如果没有任务,那么子线程处于阻塞状态
pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
}
if (shutdown)
{
// 主线程发了结束信号,那么子线程就依次退出
pthread_mutex_unlock(&m_pthreadMutex);
printf("thread %lu will exit\n", pthread_self());
pthread_exit(NULL);
}
printf("tid %lu run\n", tid);
vector<CTask*>::iterator iter = m_vecTaskList.begin();
/**
* 取出一个任务并处理之
*/
CTask* task = *iter;
if (iter != m_vecTaskList.end())
{
task = *iter;
m_vecTaskList.erase(iter);
}
pthread_mutex_unlock(&m_pthreadMutex);
task->Run(); /** 执行任务 */
printf("tid:%lu idle\n", tid);
}
return (void*)0;
}
/**
* 往任务队列里边添加任务并发出线程同步信号
*/
int CThreadPool::AddTask(CTask *task)
{
// 这里又对任务队列进行了访问,所以要加同步锁
pthread_mutex_lock(&m_pthreadMutex);
this->m_vecTaskList.push_back(task);
pthread_mutex_unlock(&m_pthreadMutex);
pthread_cond_signal(&m_pthreadCond);
return 0;
}
/**
* 创建线程
*/
int CThreadPool::Create()
{
pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);
for(int i = 0; i < m_iThreadNum; i++)
{
// 创建线程,并设置回调函数
pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);
}
return 0;
}
/**
* 停止所有线程
*/
int CThreadPool::StopAll()
{
/** 避免重复调用 */
if (shutdown)
{
return -1;
}
printf("Now I will end all threads!!/n");
/** 唤醒所有等待线程,线程池要销毁了 */
shutdown = true;
// 因为子线程可能都阻塞在等待任务到来阶段,所以需要广播条件信号量
pthread_cond_broadcast(&m_pthreadCond);
/** 阻塞等待线程退出,否则就成僵尸了 */
for (int i = 0; i < m_iThreadNum; i++)
{
// pthread_join,是等待相应的子线程结束,然后回收资源,如果子线程没有结束的话,主线程是会阻塞在这里的
// 所以这个方法常常用语,主线程来等待子线程执行完任务后,然后回收资源,退出
pthread_join(pthread_id[i], NULL);
}
free(pthread_id);
pthread_id = NULL;
/** 销毁条件变量和互斥体 */
pthread_mutex_destroy(&m_pthreadMutex);
pthread_cond_destroy(&m_pthreadCond);
return 0;
}
/**
* 获取当前队列中任务数
*/
int CThreadPool::getTaskSize()
{
return m_vecTaskList.size();
}
具体调用
int main()
{
CMyTask taskObj = new CMyTask;
char szTmp[] = "this is the first thread running";
taskObj.SetData((void*)szTmp);
CThreadPool threadPool(5);
for(int i = 0; i < 5; i++)
{
threadPool.AddTask(&taskObj);
}
while(1)
{
printf("there are still %d tasks need to handle\n", threadPool.getTaskSize());
if (threadPool.getTaskSize() == 0)
{
if (threadPool.StopAll() == -1)
{
printf("Now I will exit from main\n");
break;
}
}
// 主线程,等待子线程执行完任务
sleep(2);
}
return 0;
}
整理
main.cpp
#include "Thread.h"
#include <iostream>
class CMyTask: public CTask
{
public:
CMyTask(){}
inline int Run()
{
// printf("%s\n", (char*)this->m_ptrData);
sleep(10);
return 0;
}
};
int main()
{
CMyTask taskObj;
char szTmp[] = "this is the first thread running";
taskObj.SetData((void*)szTmp);
CThreadPool threadPool(5);
for(int i = 0; i < 5; i++)
{
threadPool.AddTask(&taskObj);
}
while(1)
{
printf("there are still %d tasks need to handle\n", threadPool.getTaskSize());
if (threadPool.getTaskSize() == 0)
{
if (threadPool.StopAll() == -1)
{
printf("Now I will exit from main\n");
break;
}
}
sleep(2);
}
return 0;
}
Thread.h
#ifndef __THREAD_H
#define __THREAD_H
#include <vector>
#include <string>
#include <pthread.h>
using namespace std;
/**
* 执行任务的类,设置任务数据并执行
*/
class CTask
{
protected:
string m_strTaskName; /** 任务的名称 */
void* m_ptrData; /** 要执行的任务的具体数据 */
public:
CTask(){}
CTask(string taskName)
{
m_strTaskName = taskName;
m_ptrData = NULL;
}
virtual int Run()= 0;
void SetData(void* data); /** 设置任务数据 */
public:
virtual ~CTask(){}
};
/**
* 线程池管理类的实现
*/
class CThreadPool
{
private:
static vector<CTask*> m_vecTaskList; /** 任务列表 */
static bool shutdown; /** 线程退出标志 */
int m_iThreadNum; /** 线程池中启动的线程数 */
pthread_t *pthread_id;
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 = 10);
int AddTask(CTask *task); /** 把任务添加到任务队列中 */
int StopAll(); /** 使线程池中的线程退出 */
int getTaskSize(); /** 获取当前任务队列中的任务数 */
};
#endif
Thread.cpp
#include "Thread.h"
#include <iostream>
void CTask::SetData(void * data)
{
m_ptrData = data;
}
vector<CTask*> CThreadPool::m_vecTaskList; //任务列表
bool CThreadPool::shutdown = false;
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;
cout << "I will create " << threadNum << " threads" << endl;
Create();
}
/**
* 线程回调函数
*/
void* CThreadPool::ThreadFunc(void* threadData)
{
pthread_t tid = pthread_self();
while (1)
{
pthread_mutex_lock(&m_pthreadMutex);
while (m_vecTaskList.size() == 0 && !shutdown)
{
pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
}
if (shutdown)
{
pthread_mutex_unlock(&m_pthreadMutex);
printf("thread %lu will exit\n", pthread_self());
pthread_exit(NULL);
}
printf("tid %lu run\n", tid);
vector<CTask*>::iterator iter = m_vecTaskList.begin();
/**
* 取出一个任务并处理之
*/
CTask* task = *iter;
if (iter != m_vecTaskList.end())
{
task = *iter;
m_vecTaskList.erase(iter);
}
pthread_mutex_unlock(&m_pthreadMutex);
task->Run(); /** 执行任务 */
printf("tid:%lu idle\n", tid);
}
return (void*)0;
}
/**
* 往任务队列里边添加任务并发出线程同步信号
*/
int CThreadPool::AddTask(CTask *task)
{
pthread_mutex_lock(&m_pthreadMutex);
this->m_vecTaskList.push_back(task);
pthread_mutex_unlock(&m_pthreadMutex);
pthread_cond_signal(&m_pthreadCond);
return 0;
}
/**
* 创建线程
*/
int CThreadPool::Create()
{
pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);
for(int i = 0; i < m_iThreadNum; i++)
{
pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);
}
return 0;
}
/**
* 停止所有线程
*/
int CThreadPool::StopAll()
{
/** 避免重复调用 */
if (shutdown)
{
return -1;
}
printf("Now I will end all threads!!/n");
/** 唤醒所有等待线程,线程池要销毁了 */
shutdown = true;
pthread_cond_broadcast(&m_pthreadCond);
/** 阻塞等待线程退出,否则就成僵尸了 */
for (int i = 0; i < m_iThreadNum; i++)
{
pthread_join(pthread_id[i], NULL);
}
free(pthread_id);
pthread_id = NULL;
/** 销毁条件变量和互斥体 */
pthread_mutex_destroy(&m_pthreadMutex);
pthread_cond_destroy(&m_pthreadCond);
return 0;
}
/**
* 获取当前队列中任务数
*/
int CThreadPool::getTaskSize()
{
return m_vecTaskList.size();
}
不足
本文采用的是pthread实现C++多线程,因为C++11之前是没有多线程标准库的,而且这个实现,不支持线程个数的动态增长,创建子线程的个数与任务量有关。
C++线程池总结的更多相关文章
- 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...
- C#多线程之线程池篇3
在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...
- C#多线程之线程池篇2
在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...
- C#多线程之线程池篇1
在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...
- NGINX引入线程池 性能提升9倍
1. 引言 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为 ...
- Java线程池解析
Java的一大优势是能完成多线程任务,对线程的封装和调度非常好,那么它又是如何实现的呢? jdk的包下和线程相关类的类图. 从上面可以看出Java的线程池主的实现类主要有两个类ThreadPoolEx ...
- Android线程管理之ExecutorService线程池
前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...
- Android线程管理之ThreadPoolExecutor自定义线程池
前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...
- -Android -线程池 批量上传图片 -附php接收代码
(出处:http://www.cnblogs.com/linguanh/) 目录: 1,前序 2,类特点 3,用法 4,java代码 5,php代码 1,前序 还是源于重构,看着之前为赶时间写着的碎片 ...
- C#多线程--线程池(ThreadPool)
先引入一下线程池的概念: 百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小,以默认的优先级运行, ...
随机推荐
- tarjan求强连通分量+缩点 模板
#define N 100100 #define M 200200 int n,m; int id,index; //id表示缩点后点的id,index表示进行tarjan算法时访问的点先后 int ...
- 《从零开始学Swift》学习笔记(Day 58)—— Swift编码规范之变量或常量声明规范
原创文章,欢迎转载.转载请注明:关东升的博客 声明是在声明变量.常量.属性.方法或函数和自定义类型时候需要遵守的规范. 首先变量或常量时每行声明变量或常量的数量推荐一行一个,因为这样以利于写注释.示例 ...
- [hihoCoder] Trie树
This is a application of the Trie data structure, with minor extension. The critical part in this pr ...
- Powershell数据处理
1.导出csv文档 Export-Csv D:\ps\xxx.csv -Encoding UTF8 -NoTypeInformation 2.发送mail $from="frommailad ...
- dot 使用笔记
Graphviz (英文:Graph Visualization Software的缩写)是一个由AT&T实验室启动的开源工具包,用于绘制DOT语言脚本描述的图形 sudo apt-get i ...
- client-side internet transfers
curl https://curl.haxx.se/ curl - Open Collective https://opencollective.com/curl#backers curl/curl: ...
- 2.2 - ATM+购物商城程序
要求:模拟实现一个ATM + 购物商城程序1.额度 15000或自定义2.实现购物商城,买东西加入 购物车,调用信用卡接口结账3.可以提现,手续费5%4.支持多账户登录5.支持账户间转账6.记录每月日 ...
- Linux安装redis数据库及添加环境变量
1.下载安装包 [root@localhost opt]# yum install wget [root@localhost opt]# wget http://download.redis.io/r ...
- 怎样优雅的管理ActionBar
转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/50997095 本文出自:[顾林海的博客] 前言 随着项目越来越大.页面 ...
- LINQ 获取当前数组中出现次数最多的元素
LINQ 获取当前数组中出现次数最多的元素 1 List<string> a = new List<string>(); a.Add( ...