线程池

时间:2019-11-30
本文章向大家介绍线程池,主要包括线程池使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

线程池:

  一个线程池主要由以下的四个部分构成。

  1 线程池管理器,负责创建线程和销毁线程,向工作队列中添加任务等。

  2 工作线程,线程池当中负责执行任务的线程,当任务队列为空的情况下,则该线程处于等待的状态。

一般使用信号量来跟踪当先任务队列当中任务的数量,线程处于sem_wait()的状态,等待任务队列为非空

时,竞争的区执行任务。

  3 任务接口,任务队列里面的任务都应该实现任务的接口,供工作线程调度执行,最主要的作用就是规

定了任务的入口。

  4 任务队列,所有待执行的任务放在任务队列当中,提供了一种缓冲的机制。值得注意的是对任务队列

进行操作时一定要进行加锁。

下面来详细解释一个线程池的创建实例:

  第一部分为线程池管理器,负责线程的创建和工作队列当中任务的添加,代码如下:

template<typename T>
class threadpool{
    public:
    threadpool(int thread_number,int max_requests=10000);
    ~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;//描述线程池的数组
        std::list<T*>   m_workqueue;//请求队列
        locker m_queuelocker;//保护请求队列的互斥锁
        sem m_queuestat;//当前是否有任务需要处理
        bool m_stop;//是否结束当前的线程
};

  以上的thread_number用于初始化该线程池创建的线程数,max_requests用来管理该线程池所能接受的最大任务数。

将其创建为模板类,方便该线程池能够处理各种任务。其中用locker来保护任务队列,该locker里面封装的是pthread_mu

tex_t,sem里面封装的是sem_t用来体现任务对了里面的任务数目,并且用于线程之间使用竞争的方式来取得任务。

  该class的构造函数如下:

template<typename T>
threadpool<T>::threadpool(int thread_number,int max_requests):m_thread_number(thread_number),m_max_requests(max_requests),
                                                                                                                                        m_threads(NULL),m_stop(false)
{
    if(thread_number)<1||max_requests<1)
        throw std::exception();
    //创建存储线程号的数组
    m_threads = new pthread_t[m_thread_number];
    if(!m_threads)
        throw std::exception();
    //创建规定个数的线程,并将线程设置为detach()
    for(int i=0;i<thread_number;i++)
    {
        printf("create the %dth thread\n",i);
        if(pthread_create(m_threads+i,NULL,worker,this)!=0)
        {
            delete []m_threads;
            throw std::exception();
        }
        if(pthread_detach(m_threads[i]))
        {
        //分离成功的话,则返回值为0
            delete []m_threads;
            throw std::exception;
        }
    }
} 

  在c++里面使用pthread_create()函数时,传入的第三个参数务必要是静态函数,本次的构造函数将

线程池对象本身作为参数传递给了工作线程。其作为第二部分的代码如下:

template<typename T>
void* threadpool<T>::worker(void* arg){
    //工作线程的参数为空指针的类型
    threadpool* pool=(threadpool*)arg;
    pool->run();
    return pool;
}

//工作线程执行的函数
template<typename T>
void threadpool<T>::run()
{
    //m_stop全局对象用来保证,当线程执行完一个任务队列当中的任务之后仍然能够继续从
    while(!m_stop)
    {   
        //等待当前的对立面有任务
        m_queuestat.wait();
        //加锁后读取并执行队列里面的任务
        m_queuelocker.lock();
        if(m_workqueue.empty()){
            m_queuelocker.unlock();
            continue;
        }
        T* request=m_workqueue.front();
        m_workqueue.pop_front();
        m_queuelocker.unlock();
        if(!request)
            continue;
        request->process();
    }
}

  工作线程,从任务队列当中取出任务,并执行。全局变量m_stop保证了工作线程在对象销毁

之前会一直不断的从任务队列当中取出任务并执行。

  本次的线程池没有针对具体的任务形式,因此没有涉及任务接口的涉及,等以后补充。

原文地址:https://www.cnblogs.com/wangkaia/p/11952990.html