C++实现线程池(条件变量)

引言

因为多线程对于CPU的高效利用 好几种高性能的服务器框架都使用了多线程 但线程的创建和回收是非常浪费系统资源的 常常会有不必要的时间损失 但我们的服务器的硬件确相对来说非常充裕 于是我们可以初始化一组资源 在服务器运行阶段可以直接获取而不需要重新分配 相对的在一个逻辑单元执行完以后也不需要释放资源 从而大大提高了效率 避免了对内核的频繁访问 这里我们说的资源就是线程 初始化的这一组资源可以看做是一个线程池

线程池基本原理
其实线程池的内部实现就相当于是一个生产者消费者模型 线程池就是消费者 同时竞争锁 先拿到锁则获取资源 生产者则相当于我们的append操作 我们每添加一次资源 则相当于生产者生产 内部则触发一个条件变量的 signal 唤醒工作线程 下面是一个简单的实现 其中把条件变量和线程池分别封装成不同的类 方便使用

ThreadPool.h

#ifndef THREADPOOL_H_
#define THREADPOOL_H_

#include"locker.h"
#include<list>
#include<cstdio>
#include<exception>
#include<pthread.h>
#include<iostream>

template<typename T>
void solve(const T &t){
    std::cout << "线程接收到消息: " << t << std::endl;
    return;
}

template<typename T>
class threadpool{
    enum{Max_Thread = 10,Max_Requests = 10000};
    public:
        explicit threadpool(int thread_number = Max_Thread,int max_requests = Max_Requests);
        ~threadpool();
        bool append(T* request);//向任务队列中添加任务
    private:
        static void* worker(void *arg);
        void run();
    private:
        int m_thread_number;//最大线程数
        int m_max_requests;//最大请求数
        pthread_t* m_threads; //描述线程的数组
        //unique_ptr<pthread_t[]>m_threads; //如果确定数组大小 就可以用unique_ptr管理内存
        std::list<T*> m_workqueue;//任务队列
        cond m_QueueState; //条件变量 类内初始化 
        bool m_stop;
        //直接类内默认初始化失败
};

template<typename T>
threadpool<T>::threadpool(int thread_number,int max_requests):
m_thread_number(thread_number),m_max_requests(max_requests),m_stop(false),m_threads(NULL),
m_QueueState(){//默认初始化
    if(thread_number<=0 || max_requests<=0){
        throw std::out_of_range("error in initialize");
    }
    m_threads = new pthread_t[m_thread_number];
    if(!m_threads){
        throw std::bad_alloc();
    }
    //typedef void* (*Temp)(void*);
    using Temp = void* (*)(void*);
    Temp enp = (Temp)&threadpool::run;

    for(int i=0;i<m_thread_number;++i){
        if(pthread_create(&(m_threads[i]),nullptr,enp,this) != 0){
            //if(pthread_create(&(m_threads[i]),nullptr,worker,this) != 0){ //两种都可以
            delete []m_threads;
            throw std::exception();
        }
        if(int ret = pthread_detach(m_threads[i])){
            delete []m_threads;
            throw std::exception();
        }
    }
}

template<typename T>
threadpool<T>::~threadpool(){
    delete []m_threads;
    m_stop = true;
}

template<typename T>
bool threadpool<T>::append(T* requests){
    m_QueueState.lock();
    if(m_workqueue.size() >= m_max_requests){
        m_QueueState.unlock();
        return false;
    }
    m_workqueue.emplace_back(requests);
    m_QueueState.signal();
    m_QueueState.unlock();
    return true;
}

template<typename T> //这个函数本来为pthread_create的参数准备的 但有更好的解决方案 及强制类型转换
void* threadpool<T>::worker(void *arg){
    threadpool *pool = (threadpool*)arg;
    pool->run();
    return pool;  
}

template<typename T>
void threadpool<T>::run(){
    while(!m_stop){
        m_QueueState.lock();
        while(m_workqueue.empty()){
            m_QueueState.wait();
        }
        T* request = m_workqueue.front();
        m_workqueue.pop_front();
        m_QueueState.unlock();
        //这里就是线程得到这个参数后如何执行
        std::cout << pthread_self() << std::endl;
        solve(*request);
    }
}

#endif

locker.h

#ifndef LOCKER_H_
#define LOCKER_H_   
#include<exception>
#include<pthread.h>
#include<semaphore.h>//信号量

class locker{
    public:
        locker(){
            if(pthread_mutex_init(&m_mutex,nullptr)!=0){
                throw std::exception();
            }
        }
        ~locker(){
            pthread_mutex_destroy(&m_mutex);
        }
        bool lock(){
            return pthread_mutex_lock(&m_mutex) == 0;
        }
        bool unlock(){
            return pthread_mutex_unlock(&m_mutex) == 0;
        }
    private:
        pthread_mutex_t m_mutex;
};

class cond{
    public:
        cond(){
            if(pthread_mutex_init(&m_mutex,nullptr) != 0){
                throw std::exception();
            }
            if(pthread_cond_init(&m_cond,nullptr) != 0){
                pthread_mutex_destroy(&m_mutex);
                throw std::exception();
            }
        }
        ~cond(){
            pthread_mutex_destroy(&m_mutex);
            pthread_cond_destroy(&m_cond);
        }
        bool signal(){
            return pthread_cond_signal(&m_cond) == 0;
        }
        bool wait(){
            int ret = pthread_cond_wait(&m_cond, &m_mutex);
            return ret == 0;
        }
        bool lock(){
            return pthread_mutex_lock(&m_mutex) == 0;
        }
        bool unlock(){
            return pthread_mutex_unlock(&m_mutex) == 0;
        }
    private:
        pthread_mutex_t m_mutex;
        pthread_cond_t m_cond;
};

#endif 

test_for_ThreadPool.cpp

#include"ThreadPool.h"
#include<iostream>
#include<unistd.h>
using namespace std;

int flag,tmp;
int main(){
    threadpool<int> Pool(5,20000);
    while(1){
        //有可能超过最大请求数
        tmp = ++flag;
        //Pool.append(&tmp);
        //加与不加while循环效率相差几十倍 可以测试下 奇怪
        while(!Pool.append(&tmp)){
            //cout << "重 11111111111111111111111111111111111111111复\n"; return 0;
        };//加while的原因是把超过最大请求的重新发送
        //sleep(2);
    }
    return 0;
}

原文链接: https://www.cnblogs.com/lizhaolong/p/16437377.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++实现线程池(条件变量)

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/395793

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月5日 下午1:43
下一篇 2023年4月5日 下午1:43

相关推荐