线程池工作流程概述
1、初始化线程池
创建指定数量的工作线程。
初始化任务队列。
2、启动线程池
设置运行状态标志为真(m_isRuning = true)。
每个工作线程开始循环等待并处理任务。
3、添加任务
用户代码调用 addTask 方法将新任务加入到任务队列中。
如果任务队列已满,则等待直到有空位可以加入新任务。
4、执行任务
工作线程从任务队列中取出任务并执行。
如果当前没有可用任务且线程池仍在运行,则等待任务到来。
5、停止线程池
设置运行状态标志为假(m_isRuning = false),通知所有线程终止。
等待所有工作线程完成当前任务后退出。
清理资源。
总共分为Thread.h、Thread.cpp、ThreadPool.h、ThreadPool.cpp、main.cpp五个文件,详细注解见以下代码。
Thread类主要功能:
- start() 方法:配置并启动线程。使用
pthread_create
创建一个新的线程,并通过threadGuide
函数作为线程的入口点。这个方法还设置了线程的属性,如调度策略和作用域等。 - join() 方法:等待线程完成执行。通过调用
pthread_join
来阻塞当前线程直到目标线程结束。 - threadGuide 静态成员函数:这是实际的线程入口点,它接收一个指向
Thread
实例的指针,并通过该实例调用用户定义的线程例程 (m_threadRoutine
)。 - 同步机制:使用互斥锁 (
std::mutex
和std::lock_guard<std::mutex>
) 保证对共享资源(例如m_isRuning
成员变量)的访问是线程安全的。
//Thread.h
#ifndef THREAD_H
#define THREAD_H
#include<mutex>
using namespace std;
class Thread{
public:
typedef void*(*threadFun_t)(void *arg);//线程函数指针类
explicit Thread(const threadFun_t &threadRoutine,void*arg);
~Thread();
void start();//启动线程
void join();//等待线程结束
static void* threadGuide(void*arg);//静态线程入口函数
pthread_t getThreadId() const{
return m_threadId;
}
private:
pthread_t m_threadId;//线程ID
bool m_isRuning;//标记线程是否正在运行
threadFun_t m_threadRoutine;//用户提供的线程函数
void*m_threadArg;//线程函数的参数
mutex m_mutex;//用于保护m_isRuning
};
#endif
#include<pthread.h>
#include<mutex>
#include<iostream>
#include<cstdlib>
#include "Thread.h"
using namespace std;
#define CHECK(condition) \
do { \
if (!(condition)) { \
std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << std::endl; \
exit(EXIT_FAILURE); \
} \
} while (0)
#define VERIFY(condition) \
do { \
if (!(condition)) { \
std::cerr << "Verify failed: " << __FILE__ << ":" << __LINE__ << std::endl; \
exit(EXIT_FAILURE); \
} \
} while (0)
Thread::Thread(const threadFun_t &threadRoutine,void* arg):m_isRuning(false),
m_threadId(0),m_threadRoutine(threadRoutine),m_threadArg(arg){
}
Thread::~Thread(){
std::lock_guard<std::mutex> lock(m_mutex);
if(m_isRuning){
join();
}
}
void *Thread::threadGuide(void*arg){
Thread*p=static_cast<Thread*>(arg);
p->m_threadRoutine(p->m_threadArg);
return NULL;
}
void Thread::join(){
lock_guard<mutex>lock(m_mutex);
if (m_isRuning) {
CHECK(!pthread_join(m_threadId, NULL));
m_isRuning = false;
}
}
void Thread::start(){
lock_guard<mutex>lock(m_mutex);
if(!m_isRuning)
{
pthread_attr_t attr;
CHECK(!pthread_attr_init(&attr));
CHECK(!pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED));
CHECK(!pthread_attr_setschedpolicy(&attr,SCHED_OTHER));
CHECK(!pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM));
//创建线程
CHECK(!pthread_create(&m_threadId,&attr,threadGuide,this));
//销毁线程属性对象
CHECK(!pthread_attr_destroy(&attr));
m_isRuning=true;
}
}
ThreadPool类主要功能:
- 管理一组工作线程:维护一个固定数量的工作线程池,以便高效地执行多个任务。
- 任务队列管理:维护一个任务队列,用于存放待处理的任务。工作线程会不断地从队列中取出任务进行处理。
- 提供接口添加任务:允许用户将新的任务添加到任务队列中,以便由线程池中的某个空闲线程执行。
- 启动和停止线程池:允许用户启动或停止整个线程池,并确保所有任务都被正确处理。
主要职责
管理一组工作线程:维护一个固定数量的工作线程池,以便高效地执行多个任务。
任务队列管理:维护一个任务队列,用于存放待处理的任务。工作线程会不断地从队列中取出任务进行处理。
提供接口添加任务:允许用户将新的任务添加到任务队列中,以便由线程池中的某个空闲线程执行。
启动和停止线程池:允许用户启动或停止整个线程池,并确保所有任务都被正确处理。
核心方法
start() 方法:
设置 m_isRuning 为 true,表示线程池开始运行。
预留空间给 m_threads 向量。
创建指定数量的线程,并将每个线程的入口点设置为 threadRoutine 函数,同时传递当前线程池实例作为参数。
调用每个线程的 start() 方法来启动线程。
stop() 方法:
设置 m_isRuning 为 false,通知所有线程终止。
使用 notify_all() 唤醒所有等待的任务空条件变量的线程。
等待所有线程完成(通过调用 join() 方法),然后删除它们并从向量中移除。
addTask(Task task) 方法:
如果线程池没有在运行,直接执行传入的任务。
否则,将任务添加到任务队列中,并在必要时等待队列中有足够的空间(通过 wait() 方法)。
添加任务后,使用 notify_one() 唤醒一个等待的任务空条件变量的线程。
take() 方法:
获取一个任务以供线程执行。
使用互斥锁保护对任务队列的访问。
如果任务队列为空且线程池仍在运行,则等待直到有新任务可用(通过 wait() 方法)。
返回任务队列中的第一个任务,并从队列中移除它;如果队列为空,则返回一个空任务。
threadRoutine(void* arg) 静态成员函数:
这是每个工作线程的实际入口点。
在循环中不断尝试从线程池中取出任务并执行,直到线程池不再运行 (m_isRuning 为 false)。
Task任务:用一个简单函数表示using Task=std::function<void()>
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include<vector>
#include<iostream>
#include <condition_variable>
#include <mutex>
#include <deque>
#include <functional>
#include "Thread.h"
using namespace std;
using Task = std::function<void()>;
//线程池这里主要实现调度策略
class ThreadPool{
private:
vector<Thread *>m_threads;//线程指针数组
deque<Task>m_tasks;//任务队列
size_t m_tasksSize;//最大任务队列容量
size_t m_threadsSize;//线程池中的线程数量
mutex m_mutex;//互斥锁
condition_variable m_tasksEmpty;//任务为空时的条件变量
condition_variable m_tasksFull;//任务为满时的条件变量
bool m_isRuning; //标记线程池是否正在运行
public:
void start();//创建线程池
void stop();//关闭线程池
ThreadPool(size_t tasksSize,size_t threadsSize);
~ThreadPool();
static void* threadRoutine(void* arg);//从n线程池取出任务并执行
Task take();//任务获取函数
void addTask(Task task);//添加任务到线程池
};
#endif
#include "ThreadPool.h"
#include<memory>
using namespace std;
void* ThreadPool::threadRoutine(void* arg){//从线程池取出任务并执行
ThreadPool *p=static_cast<ThreadPool*>(arg);
while (p->m_isRuning)
{
Task task=p->take();
if(task)
{
task();
}
}
return nullptr;
}
ThreadPool::ThreadPool(size_t tasksSize, size_t threadsSize):
m_tasksSize(tasksSize),
m_threadsSize(threadsSize),
m_isRuning(false) {
}
ThreadPool::~ThreadPool(){
if(m_isRuning){
stop();
}
}
Task ThreadPool::take(){
unique_lock<mutex> lock(m_mutex);
while(m_tasks.empty() && m_isRuning){
m_tasksEmpty.wait(lock);
}
if(!m_tasks.empty()){
Task task=m_tasks.front();
m_tasks.pop_front();
m_tasksFull.notify_one();
return task;
}
return {};//返回空任务
}
void ThreadPool::addTask(Task task)
{
if (!m_isRuning) {
task();
}
else{
std::unique_lock<std::mutex> lock(m_mutex);
while(m_tasksSize > 0 && m_tasks.size() >= m_tasksSize){
m_tasksFull.wait(lock);
}
m_tasks.push_back(task);
m_tasksEmpty.notify_one();
}
}
void ThreadPool::start(){
std::lock_guard<std::mutex> lock(m_mutex);
m_isRuning=true;
m_threads.reserve(m_threadsSize);
for(size_t i=0;i<m_threadsSize;i++){
m_threads.push_back(new Thread(threadRoutine,this));
m_threads[i]->start();
}
}
void ThreadPool::stop(){
{
std::lock_guard<std::mutex> lock(m_mutex);
m_isRuning = false;
m_tasksEmpty.notify_all();
}
for(int i = m_threadsSize - 1; i >= 0; i--){
m_threads[i]->join();
delete(m_threads[i]);
m_threads.pop_back();
}
}
main.cpp:主函数
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <vector>
#include <iostream>
#include <unistd.h>
#include "Thread.h"
#include "ThreadPool.h"
using namespace std;
void myFunction(){
cout<<"执行我的函数"<<endl;
}
int main()
{
//初始化线程池,最大任务容量为10,线程数量为4
ThreadPool pool(10,4);
//启动线程池
pool.start();
//添加任务到线程池
for(int i=0;i<8;i++)
{
pool.addTask(myFunction);
}
//等待一段时间让线程池处理任务
sleep(5);//暂停主线程5秒
//停止线程池(等待所有任务完成,并且不会接受新任务)
pool.stop();
return 0;
}