zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    C# 不用添加WebService引用,调用WebService方法
    贪心 & 动态规划
    trie树 讲解 (转载)
    poj 2151 Check the difficulty of problems (检查问题的难度)
    poj 2513 Colored Sticks 彩色棒
    poj1442 Black Box 栈和优先队列
    啦啦啦
    poj 1265 Area(pick定理)
    poj 2418 Hardwood Species (trie树)
    poj 1836 Alignment 排队
  • 原文地址:https://www.cnblogs.com/mahaitao/p/5721415.html
Copyright © 2011-2022 走看看