【Linux】线程池

线程池:

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

线程池的应用场景

  1. 需要大量线程完成任务,且完成的时间比较短。
  2. 对性能要求苛刻的应用。
  3. 接收突发性的大量请求,但不至于使服务器因此产生大量线程的应用。

 组成

线程池的本质是生产消费模型。然是生产消费模型,也就需要一个队列来存放任务。

这个队列在多线程环境下属于公共资源,访问公共资源就需要加锁。所以一个线程池的组成就是:线程、任务队列、锁【Linux】线程池_第1张图片

 代码

LockGuard.hpp

这个是管理锁的类。

#pragma once

#include 
#include 

class Mutex
{
public:
    Mutex(pthread_mutex_t *lock_p = nullptr): lock_p_(lock_p)
    {}
    void lock()
    {
        if(lock_p_) pthread_mutex_lock(lock_p_);
    }
    void unlock()
    {
        if(lock_p_) pthread_mutex_unlock(lock_p_);
    }
    ~Mutex()
    {}
private:
    pthread_mutex_t *lock_p_;
};

class LockGuard
{
public:
    LockGuard(pthread_mutex_t *mutex): mutex_(mutex)
    {
        mutex_.lock(); 
    }
    ~LockGuard()
    {
        mutex_.unlock(); 
    }
    
private:
    Mutex mutex_;
};

Thread.hpp

这个是封装的线程类

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 

namespace ThreadNs
{
    typedef std::function func_t;
    const int num = 1024;

    class Thread
    {
    private:
        // 在类内创建线程,想让线程执行对应的方法,需要将方法设置成为static
        static void *start_routine(void *args) // 类内成员,有缺省参数
        {
            Thread *_this = static_cast(args);
            return _this->callback();
        }
    public:
        Thread()
        {
            char namebuffer[num];
            snprintf(namebuffer, sizeof namebuffer, "thread-%d", threadnum++);
            name_ = namebuffer;
        }

        void start(func_t func, void *args = nullptr)
        {
            func_ = func;
            args_ = args;
            int n = pthread_create(&tid_, nullptr, start_routine, this);
            assert(n == 0);                                            
            (void)n;
        }

        void join()
        {
            int n = pthread_join(tid_, nullptr);
            assert(n == 0);
            (void)n;
        }

        std::string threadname()
        {
            return name_;
        }

        ~Thread()
        {
        }
        void *callback() { return func_(args_);}
    private:
        std::string name_;
        func_t func_;
        void *args_;
        pthread_t tid_;

        static int threadnum;
    };
    int Thread::threadnum = 1;
}

 ThreadPool.hpp

线程池类 

#pragma once

#include "Thread.hpp"
#include "LockGuard.hpp"
#include 
#include 
#include 
#include 
#include 

using namespace ThreadNs;

const int gnum = 10;

template 
class ThreadPool;

template 
class ThreadData
{
public:
    ThreadPool *threadpool;
    std::string name;

public:
    ThreadData(ThreadPool *tp, const std::string &n) : threadpool(tp), name(n)
    {
    }
};

template 
class ThreadPool
{
private:
    static void *handlerTask(void *args)
    {
        ThreadData *td = (ThreadData *)args;
        while (true)
        {
            T t;
            {
                LockGuard lockguard(td->threadpool->mutex());
                while (td->threadpool->isQueueEmpty())
                {
                    td->threadpool->threadWait();
                }
                t = td->threadpool->pop();
            }
            std::cout << td->name << " 获一取了个任务: " << t.toTaskString() << " 并处理完成,结果是:" << t() << std::endl;
        }
        delete td;
        return nullptr;
    }

public:
    void lockQueue() { pthread_mutex_lock(&_mutex); }
    void unlockQueue() { pthread_mutex_unlock(&_mutex); }
    bool isQueueEmpty() { return _task_queue.empty(); }
    void threadWait() { pthread_cond_wait(&_cond, &_mutex); }
    T pop()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }
    pthread_mutex_t *mutex()
    {
        return &_mutex;
    }

public:
    ThreadPool(const int &num = gnum) : _num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; i++)
        {
            _threads.push_back(new Thread());
        }
    }


    void run()
    {
        for (const auto &t : _threads)
        {
            ThreadData *td = new ThreadData(this, t->threadname());
            t->start(handlerTask, td);
            std::cout << t->threadname() << " start ..." << std::endl;
        }
    }
    void push(const T &in)
    {
        LockGuard lockguard(&_mutex);
        _task_queue.push(in);
        pthread_cond_signal(&_cond);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (const auto &t : _threads)
            delete t;
    }

private:
    int _num;  //线程的数量
    std::vector _threads;
    std::queue _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};

 Task.hpp

任务类

#pragma once

#include 
#include 
#include 
#include 

class Task
{
    using func_t = std::function;
public:
    Task()
    {}
    Task(int x, int y, char op, func_t func)
    :_x(x), _y(y), _op(op), _callback(func)
    {}
    std::string operator()()
    {
        int result = _callback(_x, _y, _op);
        char buffer[1024];
        snprintf(buffer, sizeof buffer, "%d %c %d = %d", _x, _op, _y, result);
        return buffer;
    }
    std::string toTaskString()
    {
        char buffer[1024];
        snprintf(buffer, sizeof buffer, "%d %c %d = ?", _x, _op, _y);
        return buffer;
    }
private:
    int _x;
    int _y;
    char _op;
    func_t _callback;
};


int mymath(int x, int y, char op)
{
    int result = 0;
    switch (op)
    {
    case '+':
        result = x + y;
        break;
    case '-':
        result = x - y;
        break;
    case '*':
        result = x * y;
        break;
    case '/':
    {
        if (y == 0)
        {
            std::cerr << "div zero error!" << std::endl;
            result = -1;
        }
        else
            result = x / y;
    }
        break;
    case '%':
    {
        if (y == 0)
        {
            std::cerr << "mod zero error!" << std::endl;
            result = -1;
        }
        else
            result = x % y;
    }
        break;
    default:
        break;
    }

    return result;
}

 main.cc

【Linux】线程池_第2张图片

 测试结果

【Linux】线程池_第3张图片 

单例模式版线程池

单例模式

某些类, 只应该具有一个对象(实例), 就称之为单例。单例模式有俩种实现方式:饿汉和懒汉

饿汉方式实现单例模式

template 
class Singleton { 
  static T data; 
public:  
  static T* GetInstance() {  
    return &data;
   } 
}; 

 懒汉方式实现单例模式

template  
class Singleton {   
  static T* inst; 
public:   
  static T* GetInstance() {   
  if (inst == NULL) {       
     inst = new T();    
  }    
  return inst; 
 }
}; 

 这里存在一个严重的问题:线程不安全。

第一次调用 GetInstance 的时候, 如果两个线程同时调用, 可能会创建出两份 T 对象的实例.

懒汉方式实现单例模式(线程安全版本) 

// 懒汉模式, 线程安全、
template 
class Singleton
{
    volatile static T *inst; // 需要设置 volatile 关键字, 否则可能被编译器优化. static 
    std::mutex lock;

public:
    static T *GetInstance()
    {

        if (inst == NULL)
        { // 双重判定空指针, 降低锁冲突的概率, 提高性能.
            lock.lock(); // 使用互斥锁, 保证多线程情况下也只调用一次 new.
            if (inst == NULL)
            {
                inst = new T();
            }

            lock.unlock();
        }
        return inst;
    }
};

线程池的懒汉模式【线程安全】

【Linux】线程池_第4张图片【Linux】线程池_第5张图片

你可能感兴趣的:(Linux,linux,运维,服务器)