线程池的简单实现

本文介绍了线程池的概念,其能避免频繁创建和销毁线程的开销,适合处理大量短时间任务。线程池在WEB服务器、性能要求高的应用和应对突发请求的场景下尤为适用。文中给出了线程池的简单实现,包括类成员变量、构造析构函数、初始化、线程执行函数和任务处理。最后通过加减乘除任务测试了线程池的运行情况。
摘要由CSDN通过智能技术生成

线程池的概念

在学习使用stl容器的时候,我们见到了stl容器使用了内存池来进行时间优化,因为用户在使用new、malloc等向系统申请空间的时候,身份会发生变化,同时有可能要执行操作系统内的内存处理算法,这可能会比较耗时。于是使用了内存池来提前申请好大块内存空间,需要用户自行进行管理。与内存池类似,提前准备好的线程,用来随时处理任务,这就被称作线程池。
线程池是线程的一种使用模式。线程过多会带来调度开销,从而影响缓存局部性和整体性能。而线程池中维护着多个线程,等待分配可并发执行的任务。这就避免了在处理短时间任务时创建和销毁线程的代价。线程池不仅能保证内核的充分利用,还能防止过度调度。可用线程数量取决于可用的并发处理器、处理器内核、内网络sockets等的数量。

线程池的应用场景

  1. 需要大量的线程来完成任务,并且完成任务的时间比较短。WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,任务数量巨大。但是对于长时间的任务,比如一共Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
  2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
  3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池的情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,可能会出现错误。

线程池的简单实现

线程池的实现可以先使用一个命名空间来封装这个类。线程池中类的成员变量有:num_代表该线程池中有多少个线程。task_queue_代表一个队列,该成员是一个临界资源,用来存放任务。还有一把锁和一个条件变量。

#include<iostream>
#include<string>
#include<queue>
#include<unistd.h>

namespace ns_threadpool
{
   
    const int g_num = 5;

    template<class T>
    class ThreadPool
    {
   
        private:
        int num_;
        std::queue<T> task_queue_;//该成员是一个临界资源
        pthread_mutex_t mtx_;
        pthread_cond_t cond_;

    };
} // namespace ns_threadpool

线程池中的构造和析构函数:主要是对锁和条件变量进行初始化和销毁操作,并对具体创建线程的数量进行初始化

        ThreadPool(int num = g_num)
            :num_(num)
        {
   
            pthread_mutex_init(&mtx_,nullptr);
            pthread_cond_init(&cond_,nullptr);
        }
        ~ThreadPool()
        {
   
            pthread_mutex_destroy(&mtx_);
            pthread_cond_destroy(&cond_);
        }

初始化线程池:初始化线程池即创建num_数量的线程,这里只需要创建出来即可,不需要等待等操作。需要注意的是这里需要传入this指针,具体原因后面介绍Routine函数时进行介绍

        void InitThreadPool()
        {
   
            pthread_t tid;
            for(int i=0;i<num_;i++)
            {
   
                pthread_create(&tid,nullptr,Routine,(void*)this);
            }
        }

Routine线程执行函数:该函数由于是在类里面,所以如果不加上static来进行修饰,则会自带一个隐藏的this指针,这就和创建线程所需要的函数不符合,因此需要加上static。但是加上static后就不能访问类中的内容,因此之前在创建线程的时候刚好可以将this指针传入。
在该函数的实现方面可以先将线程进行分离再进行后续的处理工作。
为了线程安全还是需要对临界资源的访问进行加锁操作。使用条件变量来控制判断此时是否有任务需要执行,如果没有任务需要执行则等待,有则进行任务处理工作。

        static void* Routine(void* args)
        {
   

            pthread_detach(pthread_self());
            ThreadPool<T>* tp = (ThreadPool<T>*)args;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值