Linux线程池

线程池

线程过多会带来调度开销,进⽽影响缓存局部性和整体性能。⽽线程池维护着多个线程,等待着监督管理者分配可并发执⾏的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利⽤,还能防⽌过分调度。可⽤线程数量应该取决于可⽤的并发处理器、处理器内核、内存、⽹络sockets等的数量。

线程池的应用场景

1.需要⼤量的线程来完成任务,且完成任务的时间⽐较短。⽐如WEB服务器完成⽹⻚请求这样的任

务,使⽤线程池技术是⾮常合适的。因为单个任务⼩,⽽任务数量巨⼤,你可以想象⼀个热⻔⽹站

的点击次数。?但对于⻓时间的任务,⽐如⼀个Telnet连接请求,线程池的优点就不明显了。因为

Telnet会话时间⽐线程的创建时间⼤多了。

2.对性能要求苛刻的应⽤,⽐如要求服务器迅速响应客⼾请求。

3.接受突发性的⼤量请求,但不⾄于使服务器因此产⽣⼤量线程的应⽤。突发性⼤量客⼾请求,在没有线程池情况下,将产⽣⼤量线程,虽然理论上⼤部分操作系统线程数⽬最⼤值不是问题,短时间内产⽣⼤量线程可能使内存到达极限,出现错误.

线程池的设计实现

上面的图就是线程池,用户往线程池中放我们的任务,由不同的线程处理函数来执行任务,这就是线程池的设计思想

cpp 复制代码
#pragma once
#include <iostream>
#include <memory>
#include <vector>
#include <queue>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"

using namespace ThreadMoudle;
using namespace CondModule;
using thread_t = std::shared_ptr<Thread>;

namespace ThreadPoolMoudle
{
    int DefaultNum = 5;                               //默认线程数量
    
    template<typename T>
    class ThreadPool
    {
    public:
        ThreadPool(int num = DefaultNum)
            :_ThreadNum(num)
            ,_IsRuning(false)
        {
            for(int i = 0; i<num; i++)
            {
                _vecThreads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HanderTask,this)));
                std::cout << "线程创建完毕" << std::endl;
            }
        }
        void Start()
        {
            if(_IsRuning)
            {
                return;
            }
            _IsRuning = true;
            for(auto &e:_vecThreads)
            {
                e->Start();
            }
        }
        void Enqueue(const T &t)
        {
            LockGuard lockguard(_mutex);
            _qTask.push(t); 
            _cond.Notify();
        }
        void Wait()
        {
            for(auto &e:_vecThreads)
            {
                e->Join();
            }   
        }
        void Stop()
        {
            _IsRuning = false;
        }
    private:
        bool IsEmpty()
        {
            return _qTask.empty();
        }
        void HanderTask()
        {
            while(true)
            {
                T t;
                { 
                    LockGuard lockguard(_mutex);
                    while(IsEmpty()&&_IsRuning)
                    {
                        _cond.Wait(_mutex);
                    }
                    if(IsEmpty()&&!_IsRuning)
                    {
                        //任务队列为空了但是线程还在运行直接退出
                        break;
                    }
                    t = _qTask.front();
                    _qTask.pop();   
                }
               t();
            }
        }
    private:
        std::vector<thread_t> _vecThreads;              //线程
        std::queue<T> _qTask;                           //线程要处理的任务
        int _ThreadNum;                                 //线程数量
        Mutex _mutex;
        Cond _cond;
        bool _IsRuning;                                 //线程是否在运行
    };
}

测试文件

cpp 复制代码
#include <memory>
#include <functional>
#include "ThreadPool.hpp"
using namespace ThreadPoolMoudle;

using func_t = std::function<void()>;
Mutex mutex;
int ncnt = 1;
void push()
{
    printf("ncnt: %d\n",ncnt++);
    sleep(1);
}

int main()
{
    std::unique_ptr<ThreadPool<func_t>> tpf = std::make_unique<ThreadPool<func_t>>(); 
    tpf->Start();
    int count = 40;
    while(count--)
    {
        tpf->Enqueue(push); 
    }
    tpf->Stop();
    tpf->Wait();

    return 0;
}

运行结果

单例模式

单例模式就是保证我们的类只能够定义出一个对象,对于线程池来说,如果创建多个线程池的话,线程数量太多了,就会造成资浪费,调度混乱,单例模式的设置需要使用static关键字,因为static修饰的变量所有类共享这个类

cpp 复制代码
#pragma once
#include <iostream>
#include <memory>
#include <vector>
#include <queue>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"

using namespace ThreadMoudle;
using namespace CondModule;
using namespace LockModule;
using thread_t = std::shared_ptr<Thread>;

namespace ThreadPoolMoudle
{
    int DefaultNum = 5;                               //默认线程数量
    
    template<typename T>
    class ThreadPool
    {
    public:
        void Enqueue(const T &t)
        {
            LockGuard lockguard(_mutex);
            _qTask.push(t); 
            _cond.Notify();
        }

        void Start()
        {
            for(auto &e:_vecThreads)
            {
                e->Start();
            }
           
        }
        void Wait()
        {
            for (auto &thread_ptr : _vecThreads)
            {
                thread_ptr->Join();
            }
        }
        static ThreadPool<T> *GetInstance()
        {
            if(nullptr == Instance)
            {
                LockGuard lockguard(mutex);
                if(nullptr == Instance)
                {
                    Instance = new ThreadPool<T>();
                    Instance->Start();
                }
            }
            return Instance;
        }
        ThreadPool(const ThreadPool<T> &) = delete;                      //禁止拷贝
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;          
    private:
        ThreadPool(int num = DefaultNum)
            :_ThreadNum(num)
        {
            for(int i = 0; i<num; i++)
            {
                _vecThreads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HanderTask,this)));
                std::cout << "线程创建完毕" << std::endl;
            }
        }
        bool IsEmpty()
        {
            return _qTask.empty();
        }
        void HanderTask()
        {
            while(true)
            {
                T t;
                { 
                    LockGuard lockguard(_mutex);
                    while(IsEmpty())
                    {
                        _cond.Wait(_mutex);
                    }
                    t = _qTask.front();
                    _qTask.pop();
                }
                t();
            }
        }
    private:
        std::vector<thread_t> _vecThreads;              //线程
        std::queue<T> _qTask;                           //线程要处理的任务
        int _ThreadNum;                                 //线程数量
        Mutex _mutex;
        Cond _cond;

        static ThreadPool<T> *Instance;                 //单例模式
        static Mutex mutex;                             //用来保护单例模式
    };
    template<typename T>
    ThreadPool<T> *ThreadPool<T>::Instance = nullptr;  //类中定义,类外初始化

    template<typename T>
    Mutex ThreadPool<T>::mutex;
}

测试文件

cpp 复制代码
#include <memory>
#include <functional>
#include "ThreadPool.hpp"
using namespace ThreadPoolMoudle;

using func_t = std::function<void()>;

int ncnt = 0;
void push()
{
    while(true)
    {
        printf("ncnt: %d\n",ncnt++);
        sleep(1);
    }
}

int main()
{
    ThreadPool<func_t>::GetInstance()->Enqueue(push);
    ThreadPool<func_t>::GetInstance()->Wait();
    return 0;
}

运行结果

普通函数,需要先定义一个类的对象才能被调用,但是单例模式要求不能随便定义一个对象,而static满足了不需要定义对象就能直接调用函数的的需求