线程池代码cpp/c++实现(内附完整代码)

线程池工作流程概述

    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::mutexstd::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类主要功能:

  1. 管理一组工作线程:维护一个固定数量的工作线程池,以便高效地执行多个任务。
  2. 任务队列管理:维护一个任务队列,用于存放待处理的任务。工作线程会不断地从队列中取出任务进行处理。
  3. 提供接口添加任务:允许用户将新的任务添加到任务队列中,以便由线程池中的某个空闲线程执行。
  4. 启动和停止线程池:允许用户启动或停止整个线程池,并确保所有任务都被正确处理。

主要职责

    管理一组工作线程:维护一个固定数量的工作线程池,以便高效地执行多个任务。
    任务队列管理:维护一个任务队列,用于存放待处理的任务。工作线程会不断地从队列中取出任务进行处理。
    提供接口添加任务:允许用户将新的任务添加到任务队列中,以便由线程池中的某个空闲线程执行。
    启动和停止线程池:允许用户启动或停止整个线程池,并确保所有任务都被正确处理。

核心方法

    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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值