线程池理论部分可参考其他文章:
linux线程池的实现——bobo
基础的线程池demo
本文仅放上一个基础的线程池demo:
分为三个文件:
main.cpp
PthreadPool.cpp
PthreadPool.h
后两个文件写线程池相关应用接口
main.cpp
#include <iostream>
#include <pthread.h>//pthread_create
#include <stdio.h>//perror
#include <unistd.h>//sleep
#include <semaphore.h>
#include "PthreadPool.h"
using namespace std;
void teskone()
{
cout << "tesk1" << endl;
//每个线程执行的时候真正的业务代码写在这里
}
void tesktwo()
{
cout << "tesk2" << endl;
}
void teskthree()
{
cout << "tesk3" << endl;
}
int main(int argc, char *argv[])
{
PThreadPool *pool = new PThreadPool(4);//线程创建的合理数值应该是CPU核心数量的2倍
pool->Start();
//pool->addTask(teskone);//若函数传参,不是在面传参而是去调用传参
//pool->addTask(tesktwo);
//假如一个线程业务代码需要执行10s
//我们线程池最大数量假设只有3个,如果不断往里面添加任务,达到最大线程数
//存在阻塞排队等待可能,所以要对addtask返回值做判断
while (1)
{
if ((pool->addTask(teskone)) < 0) //存在线程池满可能,所以要对addtask返回值做判断
{
cout << "thread poll full ,please wait" << endl;
}
if ((pool->addTask(tesktwo)) < 0) //存在线程池满可能,所以要对addtask返回值做判断
{
cout << "thread poll full ,please wait" << endl;
}
if ((pool->addTask(teskthree)) < 0) //存在线程池满可能,所以要对addtask返回值做判断
{
cout << "thread poll full ,please wait" << endl;
}
sleep(1);
}
return 0;
}
PthreadPool.h
#include <stdio.h>//perror
#include <iostream>
#include <pthread.h>//线程
#include <vector>
#include <unistd.h>//sleep
#include <semaphore.h>//互斥量
using namespace std;
typedef struct
{
pthread_t pthread_id;
}THREAD_INFO;
//定义了一个函数指针,这个函数没有返回值没有参数
typedef void(*Task)(void);//定义一个指针类型的数据
//线程池
class PThreadPool
{
public:
PThreadPool(int pthread_max_count);//线程的虽大数量
void Start();//启动线程池
//静态是独立于类的,与this无关
static void *thread_handle(void*data);//线程执行函数,静态方法,因为pthread_create的第三个参数void*(*)
bool m_isQuit;//线程是否退出标志
pthread_mutex_t m_mutex;//互斥量变量
pthread_cond_t m_cond;//条件变量类型
vector<Task> taskVector;//保存任务函数向量
int addTask(Task t);
int activeThread;//活跃(正在运行的)线程数量
private:
pthread_mutex_t activeThread_mutex;//活跃线程数量的互斥量
vector < THREAD_INFO> threadInfo_vector;//保存线程信息的向量
//m开头表示类的私有成员member
int m_thread_max;//线程池是最大线程数量
int m_current_threads;//当前启动的线程数量
};
PthreadPool.cpp
#include "PthreadPool.h"
#include <stdio.h>//perror
#include <iostream>
#include <pthread.h>//线程
#include <vector>
#include <unistd.h>//sleep
#include <semaphore.h>//互斥量
#include <string.h>//memset
PThreadPool::PThreadPool(int pthread_max_count)
{
m_isQuit = false;
this->activeThread = 0;
m_thread_max = pthread_max_count;//线程池是最大线程数量
m_current_threads=0;//当前启动的线程数量
//对互斥量进行初始化
pthread_mutex_init(&m_mutex, NULL);
//条件变量初始化
pthread_cond_init(&m_cond, NULL);
}
void* PThreadPool::thread_handle(void*data)//所以的线程都会执行同一个静态方法
{
//这个是静态方法,问题在于静态方法里面不能访问this成员,所以用到了线程的第四个参数
PThreadPool *pool = (PThreadPool*)data;//传参再转换类型
while (!pool->m_isQuit)
{
pthread_mutex_lock(&pool->m_mutex);
pthread_cond_wait(&pool->m_cond, &pool->m_mutex);//条件变量等待在这边,直到addTask发信号才往下执行
cout << "wake up" << endl;
pthread_mutex_lock(&pool->activeThread_mutex); //activeThread这个变量会被很多线程同时访问,所以需要使用互斥量进行保护
pool->activeThread++;//活跃(正在运行的)线程数量+1
pthread_mutex_unlock(&pool->activeThread_mutex);
//下面写业务
//从taskVector中取第一个业务,取出来执行向量里面的函数指针,执行完就把它从列表中删除
Task t = pool->taskVector[0];
t();//这样就会执行取出来的函数
pool->taskVector.erase(pool->taskVector.begin());//删除执行完的第一个,后面的会自动补上来
pthread_mutex_unlock(&pool->m_mutex);
pthread_mutex_lock(&pool->activeThread_mutex); //activeThread这个变量会被很多线程同时访问,所以需要使用互斥量进行保护
pool->activeThread--;//活跃(正在运行的)线程数量-1
pthread_mutex_unlock(&pool->activeThread_mutex);
}
}
void PThreadPool::Start()//启动线程池
{
//这里的start是根据构造函数传递进来的线程中要创建的线程数量来创建线程
for (int i = 0; i < m_thread_max; i++)
{
pthread_t pthread_id;
//在pthread_ create 的第四个参数传 this 在线程处理函数里创建对象也能用类的属性
if (pthread_create(&pthread_id, NULL, PThreadPool::thread_handle, (void*)this) < 0)//2指定线程属性3函数指针4给线程传递的参数:类指针
{
perror("pthread create err:");
}
THREAD_INFO info;
memset(&info, 0, sizeof(THREAD_INFO));
this->threadInfo_vector.push_back(info);
}
}
int PThreadPool::addTask(Task t)
{
//cout << "activeThread " << this->activeThread+1 << endl;
//cout << "m_thread_max" << m_thread_max << endl;
if (this->activeThread == m_thread_max)//所有线程都在运行就不能再加了
{
return -1;
}
else if (this->activeThread < m_thread_max)
{
taskVector.push_back(t);//添加任务,一个函数就是一个任务
//这里唤醒刚才因为条件变量睡眠的线程
pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond);//一旦被添加进来,就会通知线程唤醒
pthread_mutex_unlock(&m_mutex);
}
}
打印结果:每1秒运行3个任务一次(若m_thread_max小于同时任务数则会拒绝运行,直到下一次循环才运行,本例因为任务只是打印所以不会出现等待提示)