【Linux】线程池

一、概念

1.线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用已经创建的线程来降低频繁创建和销毁线程所带来的资源消耗。
2.线程池是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

二、线程池的应用场景

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

三、线程池的优点

1.降低资源消耗 ,复用已创建的线程来降低创建和销毁线程的消耗。
2.提高响应速度 ,任务到达时,可以不需要等待线程的创建立即执行。
3.提高线程的可管理性,使用线程池能够统一的分配、调优和监控。

四、代码

ThreadPool.hpp

cpp 复制代码
#pragma once 
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<pthread.h>

#include"Task.hpp"
#include"Thread.hpp"
#include"lockGuard.hpp"


const int N=6;

template<class T>
class ThreadPool
{
    pthread_mutex_t* getlock()
    {
        return &_mutex;
    }
   

    void threadwait()
    {
        //挂起一个线程
        pthread_cond_wait(&_cond,&_mutex);
    }

    void threadwakeup()
    {
        //唤醒一个线程
        pthread_cond_signal(&_cond);
    }

public:
    ThreadPool(int num=N)
    :_num(num)

    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);

    }
    ~ThreadPool()
    {
        for(auto& e:_threads)
        {
            e.join();
        }
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    bool isEmpty()
    {
        return _tasks.empty();
    }

    void init()
    {
        //创建线程
        for(int i=1;i<=_num;++i) 
            //pthread_create(&_threads[i],nullptr,ThreadRoutine,this);
            _threads.push_back(Thread(i,ThreadRoutine,this));
    }
    

    void start()
    {   
        //线程启动
        for(auto& e:_threads)
        {
            e.run();
        }
    }

    void check()
    {
        for(auto& e:_threads)
        {
           std::cout<<"线程ID"<<e.threadid()<<" , "<<e.threadname()<<"is running··· "<<std::endl;
        }

    }
    //放入任务
    void pushtask(const T& task)
    {
        lockGuard lock(&_mutex);
        _tasks.push(task);
        //有新任务进来,唤醒线程去处理
        threadwakeup();
    }

    
    T poptask()
    {
        T t=_tasks.front();
        _tasks.pop();
        return t;
    }
private:
    static void* ThreadRoutine(void* args)
    {   
        pthread_detach(pthread_self());
        //指针强转成线程池对象类型;
        ThreadPool<T>* tp=static_cast<ThreadPool<T>*>(args);
        while(true)
        {
            //1.判断是否有任务
        T t;  //有->处理
        {    //无->等待
            lockGuard lock(tp->getlock());
            //如果任务队列为空,则等待
            while(tp->isEmpty())
            {
               tp->threadwait();
            }
            t=tp->poptask();//从共有区域拿到线程独立栈上;
        }
        
            t();//调用task类里面的仿函数处理任务
            std::cout << "thread handler done, result: " << t.formatRes() << std::endl;
        }
    }
private:
    
    std::vector<Thread> _threads;
    int _num;//线程池里有几个线程;

    std::queue<T> _tasks; // 使用STL的自动扩容的特性

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};

Task.hpp

cpp 复制代码
#pragma once
#include<string>
#include<iostream>


class Task
{
public:
    Task(){}
    
    Task(int x,int y,char op):_x(x),_y(y),_op(op),_result(0),_exitCode(0)  {}

    int operator()()
    {
        switch(_op)
        {   
            case '+':
                _result=_x+_y;
                break;
            case '-':
                _result=_x-_y;
                break;
            case '*':
                _result=_x*_y;
                break;
            case '/':
                {
                    if(_y==0) 
                        _exitCode=-1;
                    else   
                        _result=_x/_y;    
                }
                break;
            case '%':
                {
                    if(_y==0) 
                        _exitCode=-2;
                    else   
                        _result=_x%_y;    
                }
                break;
            default:
                break;
        }
    }

    //任务
    std::string formatArg()
    {
        return std::to_string(_x) + _op + std::to_string(_y) + "=?";
    }

    //任务处理结果
     std::string formatRes()
    {
        return std::to_string(_result) + "(" + std::to_string(_exitCode)+ ")";
    }

    ~Task() {}
   


private:
    int _x;
    int _y;
    char _op;
    int _result;
    int _exitCode;
};

lockGuard.hpp

cpp 复制代码
#pragma once

#include <pthread.h>
#include <iostream>

class Mutex//成员:加锁函数和解锁函数
{
public:
    Mutex(pthread_mutex_t* pmutex):_pmutex(pmutex)   {}
    
    void lock()
    {
        pthread_mutex_lock(_pmutex);
    }
   
       void unlock()
    {
        pthread_mutex_unlock(_pmutex);
    }
   

    ~Mutex(){}

private:
    pthread_mutex_t* _pmutex;//需要传入一个互斥量(锁)的指针;
};


//对Mutex进行二次封装;
//创建该对象时自动加锁,析构时自动解锁;
class lockGuard
{   
public:
    lockGuard(pthread_mutex_t* pmutex):_mutex(pmutex)//利用锁的指针构建Mutex对象
    {
        _mutex.lock();
    }

   ~lockGuard()
    {
        _mutex.unlock();
    }

private:
    Mutex _mutex;//类内创建对象
};

Thread.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <pthread.h>
#include <string>

class Thread
{
public:
    typedef void* (*func_t) (void*);
    typedef enum
    {
        NEW=0,
        RUNNING,
        EXITED
    }ThreadStatus;

public:
      //状态:new,running,exited
        int status()
        {
            return _status;
        }

        //线程名
        std::string threadname()
        {
            return _name;
        }

        //线程ID(共享库中的进程地址空间的虚拟地址)
        pthread_t threadid()
        {
            if(_status==RUNNING)//线程已经被创建,线程id已经输入到成员变量_tid中;
                return _tid;
            else 
            {  
                return 0;
            }
        }

public:

        //构造函数;
        Thread(int num,func_t func,void* args)//num代表第几个线程
        :_tid(0),
        _status(NEW),
        _func(func),
        _args(args)

        {
            char name[128];
            snprintf(name,sizeof(name),"thread-%d",num);
            _name=name;
        }
        
        //析构函数
        ~Thread(){}

      

        //静态成员函数不能访问类内所有成员,因为没有this指针;
        static void* runHelper(void *args)
        {
            Thread* td=(Thread*)args;
            (*td)();//调用仿函数执行线程的回调函数;
            return nullptr; 
        }

        void operator()()//仿函数
        {
            //如果函数指针不为空,则执行该函数指针指向的回调函数;
            if(_func!=nullptr)  _func(_args);
        }

        //创建线程
        void run()
        {
            //因为runHelper函数必须只能有一个void*参数,所以runHelper函数在类内必须定义为static,这样才没有this指针;
            int n=pthread_create(&_tid,nullptr,runHelper,this);
            if(n!=0) return exit(1);//线程创建失败,那么直接退出进程;
            _status=RUNNING;
        }

        //等待线程结束
        void join()
        {
            int n=pthread_join(_tid,nullptr);
            if(n!=0) 
            {
                std::cerr<<"main thread join thread "<<_name<<" error "<<std::endl;
                return;
            }
            _status=EXITED;//线程退出;
        }
       
private:
    pthread_t _tid;//线程ID(原生线程库中为该线程所创建的TCB起始虚拟地址)
    std::string _name;//线程名
    func_t _func;//线程要执行的回调
    void* _args;//线程回调函数参数
    ThreadStatus _status;//枚举类型:状态
};

main.cc

cpp 复制代码
#include<iostream>
#include<memory>
#include"ThreadPool.hpp"



using namespace std;

int main()
{   
    // unique_ptr < ThreadPool<Task> > tp(new ThreadPool<Task>(20));
    // tp->init();
    // tp->start();
    // tp->check();

    //实例化类,并且多次调用getinstance()函数;
    printf("0X%x\n", ThreadPool<Task>::getinstance());
    printf("0X%x\n", ThreadPool<Task>::getinstance());
    printf("0X%x\n", ThreadPool<Task>::getinstance());
    printf("0X%x\n", ThreadPool<Task>::getinstance());
    printf("0X%x\n", ThreadPool<Task>::getinstance());
    printf("0X%x\n", ThreadPool<Task>::getinstance());
    while(true)
    {
        // 充当生产者, 从网络中读取数据,构建成为任务,推送给线程池
        int x, y;
        char op;
        std::cout << "please Enter x> ";
        std::cin >> x;
        std::cout << "please Enter y> ";
        std::cin >> y;
        std::cout << "please Enter op(+-*/%)> ";
        std::cin >> op;

        Task t(x,y,op);
        ThreadPool<Task>::getinstance()->pushtask(t); //单例对象也有可能在多线程场景中使用!
    }


    return 0;
}

makefile

cpp 复制代码
ThreadPool:main.cc
	g++ $^ -o $@ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -f ThreadPool
相关推荐
热爱嵌入式的小许9 分钟前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
ok!ko44 分钟前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
2402_857589361 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰2 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没2 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
编程、小哥哥3 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程4 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
韩楚风4 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
莹雨潇潇4 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
陈苏同学4 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm