线程池实现

📖1. 线程池概念

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

线程池的应用场景:

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

线程池的示例:

  1. 创建固定数量线程池,循环从任务队列中获取任务对象.
  2. 获取到任务对象后,执行任务对象中的任务接口.

📖2. 线程池实现

#pragma once

#include<iostream>
#include<cassert>
#include<queue>
#include<pthread.h>
#include<sys/prctl.h>

#include "Log.hpp"


using namespace std;

int gThreadNum = 5;

template<class T>
class ThreadPool
{
public:
    ThreadPool(int threadNum = gThreadNum)
        : threadNum_(gThreadNum)
        , isStart_(false)
    {
        assert(threadNum_ > 0);
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }

    static void* threadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadPool<T>* tp = static_cast<ThreadPool<T>* >(args);
        prctl(PR_SET_NAME, "follower");
        while(1)
        {
            tp->lockQueue();
            //如果没任务就wait
            while(!tp->haveTask())
            {
                tp->waitForTask();
            }

            //这个任务被一个线程执行
            T t = tp->pop();
            tp->unlockQueue();

            int one, two;
            char oper;
            t.get(&one, &two, &oper);

            Log()<<"新线程完成计算任务: "<< one << oper << two << "=" << t.run() << "\n";
        }
    }

    //调用start, 线程池开始工作
    void start()
    {
        assert(!isStart_);
        for(int i = 0; i < threadNum_; ++i)
        {
            pthread_t temp;
            pthread_create(&temp, nullptr, threadRoutine, this);
        }
        isStart_ = true;
    }

    void push(const T& in)
    {
        lockQueue();
        taskQueue_.push(in);
        choiceThreadForHandler();
        unlockQueue();
    }

private:
    void lockQueue() { pthread_mutex_lock(&mutex_); }
    void unlockQueue() { pthread_mutex_unlock(&mutex_); }
    bool haveTask() { return !taskQueue_.empty(); }  //有无任务
    void waitForTask() { pthread_cond_wait(&cond_, &mutex_); }
    void choiceThreadForHandler() { pthread_cond_signal(&cond_); } //选择一个线程去处理

    T pop()
    {
        T temp = taskQueue_.front();
        taskQueue_.pop();
        return temp;
    }

private:
    bool isStart_;
    int threadNum_;
    queue<T> taskQueue_;  //任务队列
    pthread_mutex_t mutex_;  //互斥锁
    pthread_cond_t cond_;
};
//测试线程池
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Log.hpp"
#include <ctime>
#include <unistd.h>
#include <sys/prctl.h>

int main()
{
    prctl(PR_SET_NAME, "master");
    const string operators = "+-*/";
    ThreadPool<Task>* tp = new ThreadPool<Task>();

    tp->start();
    srand((unsigned long)time(nullptr) ^ getpid() ^ pthread_self());

    //派发任务
    while(true)
    {
        int one = rand() % 50;
        int two = rand() % 10;
        char oper = operators[rand() % operators.size()];
        Log() << "主线程派发计算任务" << one << oper << two << "=?" << "\n";
        Task t(one, two, oper);
        tp->push(t);
        sleep(1);
    }

    return 0;
}

image-20221127002353528

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默.@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值