• c++线程池的实现


    线程池编程简介:

        在 我们的服务端的程序中运用了大量关于池的概念,线程池、连接池、内存池、对象池等等。使用池的概念后可以高效利用服务器端的资源,比如没有大量的线程在系 统中进行上下文的切换,一个数据库连接池,也只需要维护一定里的连接,而不是占用很多数据库连接资源。同时它们也避免了一些耗时的操作,比如创建一个线 程,申请一个数据库连接,而且可能就只使用那么一次,然后就立刻释放刚申请的资源,效率很低。

        在我的上一篇blog中已经实现一个线程基类了,在这里我们只需要实现一个线程池类ThreadPool和该线程池调度的工作线程类WorkThread即可,而且WorkThread是继承自Thread类的。

     

    实现思路:

        一个简单的线程池的实现思路一般如下:

    1. ThreadPool中创建多个线程(WorkThreadk对象),每个线程均处于阻塞状态,等待任务的到来
    1. ThreadPool提供一个提交任务的接口,如post_job(ProcCallback func, void* data); post_job后会立即返回,不会阻塞
    2. ThreadPool维护一个空闲线程队列,当客户程序调用post_job()后,如果空闲队列中有空闲线程,则取出一个线程句柄,并设置任务再给出新任务通知事件即可,处理等待的线程捕捉到事件信号后便开始执行任务,执行完后将该线程句柄重新push到空闲线程队列中
    3. 该线程池采用回调函数方式

    首先我们实现一个WorkThread类:

    #include <pthread.h>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    typedef void(*ProcCallBack)(void *);
    
    
    
    class WorkThread;
    
    
    
    class ThreadPool
    {
        friend class WorkThread;
    public:
        ThreadPool(){}
        ~ThreadPool();
        int    start_thread_pool(size_t thread_num = 5);        //启动thread_num个线程
        int    stop_thread_pool();                                      //线束线程池
        void    destroy();                                                //销毁线程池所申请的资源
        void    post_job(ProcCallBack func, void* data);        //提交任务接口,传入回调函数地址和参数
    
    protected:
        WorkThread*    get_idle_thread();                              //从获得空闲队列中取得一个线程句柄
        void        append_idle_thread(WorkThread* pthread);    //加入到thread_vec_和idl_que_中
        void        move_to_idle_que(WorkThread* idlethread);    //将线程句柄加入到idle_que_中
    
    private:
        size_t                thr_num_;                      //线程数目
        vector<WorkThread*>        thr_vec_;        //线程句柄集合
        vector<WorkThread*>    idle_que_;     //空闲线程队列
    
    private:
        // not implement
        ThreadPool(const ThreadPool&);
        ThreadPool&    operator=(const ThreadPool&);
    };
    
    class WorkThread
    {
        friend class ThreadPool;
    public:
        WorkThread(ThreadPool* pthr_pool)
        {
            hr_pool_ = pthr_pool;
            cb_func_ = NULL;
            param_ = NULL;
        }
        ~WorkThread(){}
        void set_job(ProcCallBack func, void *param)
        {
            cb_func_ = func;
            param_ = param;
            //notify();
        }
        void run()
        {
            if (cb_func_)
            {
                cb_func_(param_);
            }
            cb_func_ = NULL;
            param_ = NULL;
            hr_pool_->move_to_idle_que(this);
        }
    private:
        ThreadPool * hr_pool_;
        ProcCallBack cb_func_;
        void*        param_;
    };

    线程池实现的关键是如何创建多个线程,并且当任务来临时可以从线程池中取一个线程(也就是去得到其中一个线程的指针),然后提交任务并执行。还有一点就是 当任务执行完后,应该将该线程句柄重新加入到空闲线程队列,所以我们将ThreadPool的指针传入给了WorkThread,thr_pool_最后 可以调用move_to_idle_que(this)来将该线程句柄移到空闲队列中。

    ThreadPool中一些关键代码的实现:
    #include"threadpool.h"
    #include<cstdio>
    
    class ThreadPool;
    int ThreadPool::start_thread_pool(size_t thread_num)
    {
        thr_num_ = thread_num;
        int    ret = 0;
        for (size_t i = 0; i < thr_num_; ++i)
        {
            WorkThread*    pthr = new WorkThread(this);
            //pthr->set_thread_id(i);
            if ((ret = pthr->hr_pool_->start_thread_pool()) != 0)
            {
                printf("start_thread_pool: failed when create a work thread: %d\n", i);
                delete pthr;
                return i;
            }
            append_idle_thread(pthr);
        }
        return thr_num_;
    }
    int ThreadPool::stop_thread_pool()
    {
        for (size_t i = 0; i < thr_vec_.size(); ++i)
        {
            WorkThread* pthr = thr_vec_[i];
            //pthr->join();
            delete pthr;
        }
        thr_vec_.clear();
        idle_que_.clear();
        return 0;
    }
    void ThreadPool::destroy()
    {
        stop_thread_pool();
    }
    void ThreadPool::append_idle_thread(WorkThread* pthread)
    {
        thr_vec_.push_back(pthread);
        idle_que_.push_back(pthread);
    }
    void ThreadPool::move_to_idle_que(WorkThread* idlethread)
    {
        idle_que_.push_back(idlethread);
    }
    WorkThread* ThreadPool::get_idle_thread()
    {
        WorkThread*    pthr = NULL;
        if (!idle_que_.empty())
        {
            vector<WorkThread*>::iterator it = idle_que_.end();
            pthr = *it;
            idle_que_.pop_back();
        }
    
        return pthr;
    }
    void ThreadPool::post_job(ProcCallBack func, void* data)
    {
        WorkThread* pthr = get_idle_thread();
        while (pthr == NULL)
        {
            //Sleep(500000);
            pthr = get_idle_thread();
        }
        pthr->set_job(func, data);
    }
    
    void count(void* param)
    {
        // do some your work, like: 
        int* pi = static_cast<int*>(param);
        int val = *pi + 1;
        printf("val=%d\n", val);
        delete pi;
    }
    int main()
    {
        //程序中使用如下:
        ThreadPool* ptp = new ThreadPool();
        ptp->start_thread_pool(3);        //启动3 个线程
        ptp->post_job(count, new int(1));        //提交任务
        ptp->post_job(count, new int(2));
        ptp->post_job(count, new int(3));
        //程序线束时
        ptp->stop_thread_pool();
        return 0;
    }
  • 相关阅读:
    编译安装LAMP之php-5.4.13、xcache-2.0及使用ab命令实现压力测试
    编译安装LAMP之MySQL-5.5.28(通用二进制格式)
    编译安装LAMP之httpd-2.4.4
    建立LAMP平台
    MySQL初步,数据类型及SQL语句
    数据库及MySQL
    PHP相关概念及配置
    CSS:页面美化和布局控制
    HTML标签:表单标签
    web概念简述,HTML学习笔记
  • 原文地址:https://www.cnblogs.com/mahaitao/p/5721415.html
Copyright © 2020-2023  润新知