C++ 线程池的封装实现

来源:互联网 发布:linux退出vi模式 编辑:程序博客网 时间:2024/04/30 02:18
为了充分利用多核的优势,我们利用多线程来进行任务处理,但线程也同样不能滥用,会带来一下几个问题:
1)线程本身存在开销,系统必须为每个线程分配如栈,TLS(线程局部存储),寄存器等。
2)线程管理会给系统带来开销,context切换同样会给系统带来成本。
3)线程本身是可以重用的资源,不需要每次都进行初始化。

所以往往在使用中,我们无需把线程与task任务进行一对一对应,只需要预先初始化有限的线程个数来处理无限的task任务即可,线程池应运而生,原理也就是如此。

线程池具体构造如下:



主要含有三个队列
  • 工作队列
  • 工作线程队列
  • 忙碌线程队列
工作队列是一个阻塞队列,任务(仿函数)任务不算被push进来(notify阻塞获取的工作线程),工作线程队列(一直不变)则从该队列中获取任务执行(wait获取,当任务队列为空时阻塞等待通知),如果获取到任务,则将线程会进入忙碌线程队列中,执行任务的仿函数,当工作完成,重新移出工作线程队列。


定义线程池专属异常:
struct TC_ThreadPool_Exception : public TC_Exception
{
    TC_ThreadPool_Exception(const string &buffer) : TC_Exception(buffer){};
    TC_ThreadPool_Exception(const string &buffer, int err) : TC_Exception(buffer, err){};
    ~TC_ThreadPool_Exception () throw (){};
};


/**
 * @brief 用通线程池类, 与tc_functor, tc_functorwrapper配合使用.
 * 
 * 使用方式说明:
 * 1 采用tc_functorwrapper封装一个调用
 * 2 用tc_threadpool对调用进行执行
 * 具体示例代码请参见:test/test_tc_thread_pool.cpp
 */

/**线程池本身继承自锁,可以帮助锁定**/
class TC_ThreadPool : public TC_ThreadLock
{
public:

    /**
     * @brief 构造函数
     *
     */
    TC_ThreadPool ();

    /**
     * @brief 析构, 会停止所有线程
     */
    ~TC_ThreadPool ();

    /**
      * @brief 初始化.
      * 
     * @param num 工作线程个数
     */
    void init(size_t num);

    /**
     * @brief 获取线程个数.
     *
     * @return size_t 线程个数
     */
    size_t getThreadNum()   { Lock sync(* this); return _jobthread. size(); }

    /**
     * @brief 获取线程池的任务数( exec添加进去的).
     *
     * @return size_t 线程池的任务数
     */
    size_t getJobNum()     { return _jobqueue. size(); }

    /**
     * @brief 停止所有线程
     */
    void stop();

    /**
     * @brief 启动所有线程
     */
    void start();

    /**
      * @brief 启动所有线程并, 执行初始化对象.
      * 
     * @param ParentFunctor
     * @param tf
     */
    template<class ParentFunctor>
    void start(const TC_FunctorWrapper< ParentFunctor> &tf)
    {
        for(size_t i = 0; i < _jobthread .size(); i++)
        {
            _startqueue. push_back(new TC_FunctorWrapper<ParentFunctor >(tf));
        }

        start();
    }

    /**
      * @brief 添加对象到线程池执行,该函数马上返回,
      *     线程池的线程执行对象
      */
    template<class ParentFunctor>
     void exec(const TC_FunctorWrapper< ParentFunctor> &tf)
    {
        _jobqueue.push_back(new TC_FunctorWrapper<ParentFunctor >(tf));
    }

    /**
     * @brief 等待所有工作全部结束(队列无任务, 无空闲线程).
     *
     * @param millsecond 等待的时间( ms), -1:永远等待
      * @return            true, 所有工作都处理完毕
      *                        false,超时退出
     */
    bool waitForAllDone(int millsecond = -1);

public:

    /**
     * @brief 线程数据基类,所有线程的私有数据继承于该类
     */
    class ThreadData
    {
    public:
        /**
         * @brief 构造
         */
        ThreadData(){};
        /**
         * @brief 析够
         */
        virtual ~ThreadData(){};

        /**
            * @brief 生成数据.
            * 
            * @ param T
         * @return ThreadData*
         */
        template<typename T>
        static T* makeThreadData()
        {
            return new T;
        }
    };

    /**
      * @brief 设置线程数据.
      * 
     * @param p 线程数据
     */
    static void setThreadData(ThreadData *p);

    /**
     * @brief 获取线程数据.
     *
     * @return ThreadData* 线程数据
     */
    static ThreadData* getThreadData();

    /**
      * @brief 设置线程数据, key需要自己维护.
      * 
     * @param pkey 线程私有数据key
     * @param p    线程指针
     */
    static void setThreadData(pthread_key_t pkey, ThreadData *p);

    /**
      * @brief 获取线程数据, key需要自己维护.
      * 
     * @param pkey 线程私有数据key
     * @return     指向线程的ThreadData*指针
     */
    static ThreadData* getThreadData(pthread_key_t pkey);

protected:

    /**
      * @brief 释放资源.
      * 
     * @param p
     */
    static void destructor(void *p);

    /**
     * @brief 初始化key
     */
    class KeyInitialize
    {
    public:
        /**
         * @brief 初始化key
         */
        KeyInitialize()
        {
            int ret = pthread_key_create(&TC_ThreadPool::g_key, TC_ThreadPool::destructor);
            if(ret != 0)
            {
                throw TC_ThreadPool_Exception("[TC_ThreadPool::KeyInitialize] pthread_key_create error", ret);
            }
        }

        /**
         * @brief 释放key
         */
        ~KeyInitialize()
        {
            pthread_key_delete(TC_ThreadPool::g_key);
        }
    };

    /**
     * @brief 初始化key的控制
     */
    static KeyInitialize g_key_initialize;

    /**
     * @brief 数据key
     */
    static pthread_key_t g_key;

protected:
    /**
     * @brief 线程池中的工作线程
     */
    class ThreadWorker : public TC_Thread
    {
    public:
        /**
            * @brief 工作线程构造函数.
            * 
         * @ param tpool
         */
        ThreadWorker(TC_ThreadPool *tpool);

        /**
         * @brief 通知工作线程结束
         */
        void terminate();

    protected:
        /**
         * @brief 运行
         */
        virtual void run();

    protected:
        /**
         * 线程池指针
         */
        TC_ThreadPool   * _tpool;

        /**
         * 是否结束线程
         */
        bool            _bTerminate;
    };

protected:

    /**
     * @brief 清除
     */
    void clear();

    /**
     * @brief 获取任务, 如果没有任务, 则为NULL.
     *
     * @return TC_FunctorWrapperInterface*
     */
    TC_FunctorWrapperInterface * get(ThreadWorker *ptw);

    /**
     * @brief 获取启动任务.
     *
     * @return TC_FunctorWrapperInterface*
     */
    TC_FunctorWrapperInterface * get();

    /**
      * @brief 空闲了一个线程.
      * 
     * @param ptw
     */
    void idle(ThreadWorker *ptw);

    /**
     * @brief 通知等待在任务队列上的工作线程醒来
     */
    void notifyT();

    /**
     * @brief 是否处理结束.
     *
     * @return bool
     */
    bool finish();

    /**
     * @brief 线程退出时调用
     */
    void exit();

    friend class ThreadWorker;
protected:

    /**
     * 任务队列
     */
    TC_ThreadQueue< TC_FunctorWrapperInterface*> _jobqueue;

    /**
     * 启动任务
     */
    TC_ThreadQueue< TC_FunctorWrapperInterface*> _startqueue;

    /**
     * 工作线程
     */
    std::vector<ThreadWorker *>                  _jobthread;

    /**
     * 繁忙线程
     */
    std::set<ThreadWorker *>                     _busthread;

    /**
     * 任务队列的锁
     */
    TC_ThreadLock                               _tmutex;

     /**
      * 是否所有任务都执行完毕
      */
     bool                                        _bAllDone;
};



工作线程设计如下:
TC_ThreadPool ::ThreadWorker::ThreadWorker(TC_ThreadPool *tpool)
_tpool (tpool)
_bTerminate ( false)
{
}

void TC_ThreadPool ::ThreadWorker::terminate()
{
    _bTerminate = true;
    _tpool->notifyT();
}

void TC_ThreadPool ::ThreadWorker::run()
{
    //调用初始化部分
    TC_FunctorWrapperInterface *pst = _tpool->get();
    if(pst)
    {
        try
        {
            (*pst)();
        }
        catch ( ... )
        {
        }
        delete pst;
        pst = NULL;
    }

    //调用处理部分
    while (! _bTerminate)
    {
        TC_FunctorWrapperInterface *pfw = _tpool->get( this);
        if(pfw != NULL)
        {
            auto_ptr< TC_FunctorWrapperInterface> apfw(pfw);

            try
            {
                (*pfw)();
            }
            catch ( ... )
            {
            }

            _tpool->idle( this);
        }
    }

    //结束
    _tpool->exit();
}

每个工作线程在刚开始时都会执行一下初始化操作,并进入一个无限循环的部分//调用处理部分
    while (! _bTerminate)
    {
        TC_FunctorWrapperInterface *pfw = _tpool->get( this);
        if(pfw != NULL)
        {
            auto_ptr< TC_FunctorWrapperInterface> apfw(pfw);

            try
            {
                (*pfw)();
            }
            catch ( ... )
            {
            }

            _tpool->idle( this);
        }
    }
该工作主要是无限的从线程池的工作队列中获取任务并执行,如果成功获取任务,则会将线程移进忙碌队列:

TC_FunctorWrapperInterface *TC_ThreadPool:: get(ThreadWorker *ptw)
{

    TC_FunctorWrapperInterface *pFunctorWrapper = NULL;
    if(! _jobqueue. pop_front(pFunctorWrapper, 1000))
    {
        return NULL;
    }

     {
            Lock sync( _tmutex);
         _busthread. insert(ptw);
    }
    return pFunctorWrapper;
}

执行完,移回工作线程队列:_tpool->idle( this);

void TC_ThreadPool:: idle(ThreadWorker *ptw)
{
    Lock sync( _tmutex);
    _busthread. erase(ptw);

    //无繁忙线程, 通知等待在线程池结束的线程醒过来
    if( _busthread. empty())
    {
        _bAllDone = true;
        _tmutex.notifyAll();
    }
}


此处jobThread队列初始化后不会改变(因为没有实现自增长功能),所以非线程安全的vector队列即可,busthread的忙碌线程队列会被移进移出,但是操作会自带Lock sync( _tmutex),该互斥量是线程池本身继承的,所以是共有的,也无需另外使用线程安全的TC_ThreadQueue,使用vector即可。

TC_ThreadPool:: idle中的

    if( _busthread. empty())
    {
        _bAllDone = true;
        _tmutex.notifyAll();
    }

主要用于当线程池工作起来后的waitForAllDone方法:

bool TC_ThreadPool:: waitForAllDone( int millsecond)
{
    Lock sync( _tmutex);

start1:
    //任务队列和繁忙线程都是空的
    if (finish())
    {
        return true;
    }

    //永远等待
    if(millsecond < 0)
    {
        _tmutex.timedWait(1000);
        goto start1;
    }

    int64_t iNow = TC_Common:: now2ms();
    int m       = millsecond;
start2:

    bool b = _tmutex.timedWait(millsecond);
    //完成处理了
    if(finish())
    {
        return true;
    }

    if(!b)
    {
        return false;
    }

    millsecond = max((int64_t )0, m  - (TC_Common ::now2ms() - iNow));
    goto start2;

    return false;
}

_tmutex.timedWait(millsecond)方法唤醒。反复判断是否所有的工作是否完成:

bool TC_ThreadPool:: finish()
{
    return _startqueue. empty() && _jobqueue .empty() && _busthread. empty() && _bAllDone;
}


整体cpp实现如下:

TC_ThreadPool ::KeyInitialize TC_ThreadPool::g_key_initialize;
pthread_key_t TC_ThreadPool::g_key ;

void TC_ThreadPool::destructor( void *p)
{
    ThreadData *ttd = ( ThreadData*)p;
    if(ttd)
    {
        delete ttd;
    }
}

void TC_ThreadPool::exit()
{
    TC_ThreadPool:: ThreadData *p = getThreadData();
    if(p)
    {
        delete p;
        int ret = pthread_setspecific( g_keyNULL );
        if(ret != 0)
        {
            throw TC_ThreadPool_Exception ("[TC_ThreadPool::setThreadData] pthread_setspecific error", ret);
        }
    }

    _jobqueue. clear();
}

void TC_ThreadPool::setThreadData( TC_ThreadPool:: ThreadData *p)
{
    TC_ThreadPool:: ThreadData *pOld = getThreadData();
    if(pOld != NULL && pOld != p)
    {
        delete pOld;
    }

    int ret = pthread_setspecific( g_key, ( void *)p);
    if(ret != 0)
    {
        throw TC_ThreadPool_Exception ("[TC_ThreadPool::setThreadData] pthread_setspecific error", ret);
    }
}

TC_ThreadPool ::ThreadData TC_ThreadPool::getThreadData ()
{
    return ( ThreadData *) pthread_getspecific( g_key);
}

void TC_ThreadPool::setThreadData( pthread_key_t pkey, ThreadData *p)
{
    TC_ThreadPool:: ThreadData *pOld = getThreadData(pkey);
    if(pOld != NULL && pOld != p)
    {
        delete pOld;
    }

    int ret = pthread_setspecific(pkey, ( void *)p);
    if(ret != 0)
    {
        throw TC_ThreadPool_Exception ("[TC_ThreadPool::setThreadData] pthread_setspecific error", ret);
    }
}

TC_ThreadPool ::ThreadData TC_ThreadPool::getThreadData( pthread_key_t pkey)
{
    return ( ThreadData *) pthread_getspecific(pkey);
}

TC_ThreadPool::TC_ThreadPool()
_bAllDone ( true)
{
}

TC_ThreadPool::~TC_ThreadPool()
{
    stop();
    clear();
}

void TC_ThreadPool::clear()
{
    std::vector< ThreadWorker *>::iterator it = _jobthread. begin();
    while(it != _jobthread. end())
    {
        delete (*it);
        ++it;
    }

    _jobthread. clear();
    _busthread. clear();
}

void TC_ThreadPool::init( size_t num)
{
    stop();

    Lock sync(* this);

    clear();

    for( size_t i = 0; i < num; i++)
    {
        _jobthread. push_back( new ThreadWorker( this));
    }
}

void TC_ThreadPool::stop()
{
    Lock sync(* this);

    std::vector< ThreadWorker *>::iterator it = _jobthread. begin();
    while(it != _jobthread. end())
    {
        if ((*it)-> isAlive())
        {
            (*it)-> terminate();
            (*it)-> getThreadControl().join ();
        }
        ++it;
    }
    _bAllDone = true;
}

void TC_ThreadPool::start()
{
    Lock sync(* this);

    std::vector< ThreadWorker *>::iterator it = _jobthread. begin();
    while(it != _jobthread. end())
    {
        (*it)-> start();
        ++it;
    }
    _bAllDone = false;
}

bool TC_ThreadPool:: finish()
{
    return _startqueue. empty() && _jobqueue .empty() && _busthread. empty() && _bAllDone;
}

bool TC_ThreadPool::waitForAllDone( int millsecond)
{
    Lock sync( _tmutex);

start1:
    //任务队列和繁忙线程都是空的
    if (finish ())
    {
        return true;
    }

    //永远等待
    if(millsecond < 0)
    {
        _tmutex.timedWait(1000);
        goto start1;
    }

    int64_t iNow = TC_Common:: now2ms();
    int m       = millsecond;
start2:

    bool b = _tmutex.timedWait(millsecond);
    //完成处理了
    if(finish ())
    {
        return true;
    }

    if(!b)
    {
        return false;
    }

    millsecond = max((int64_t )0, m  - (TC_Common ::now2ms() - iNow));
    goto start2;

    return false;
}

TC_FunctorWrapperInterface *TC_ThreadPool::get( ThreadWorker *ptw)
{

    TC_FunctorWrapperInterface *pFunctorWrapper = NULL;
    if(! _jobqueue. pop_front(pFunctorWrapper, 1000))
    {
        return NULL;
    }

     {
            Lock sync( _tmutex);
         _busthread. insert(ptw);
    }
    return pFunctorWrapper;
}

TC_FunctorWrapperInterface *TC_ThreadPool::get()
{
    TC_FunctorWrapperInterface *pFunctorWrapper = NULL;
    if(! _startqueue. pop_front(pFunctorWrapper))
    {
        return NULL;
    }

    return pFunctorWrapper;
}

void TC_ThreadPool::idle( ThreadWorker *ptw)
{
    Lock sync( _tmutex);
    _busthread. erase(ptw);

    //无繁忙线程, 通知等待在线程池结束的线程醒过来
    if( _busthread. empty())
    {
            _bAllDone = true;
        _tmutex.notifyAll();
    }
}

void TC_ThreadPool::notifyT()
{
    _jobqueue. notifyT();
}
  
0 0