ZLToolKit源码阅读:线程池

1059 篇文章 285 订阅

基于任务队列(TaskQueue)和线程组(thread_group),实现线程池,线程池中所有线程等待在任务队列上,循环执行:等待任务到来->获取到任务->执行任务。

在这里插入图片描述
ThreadPool继承自TaskExecutor,TaskExecutor又同时继承了ThreadLoadCounter和TaskExecutorInterface,所以线程池支持负载统计、同步以及异步执行任务

分析

class ThreadPool : public TaskExecutor {
public:
    enum Priority {
        PRIORITY_LOWEST = 0,
        PRIORITY_LOW,
        PRIORITY_NORMAL,
        PRIORITY_HIGH,
        PRIORITY_HIGHEST
    };

private:
    size_t _thread_num;
    TaskQueue<Task::Ptr> _queue;
    thread_group _thread_group;
    Priority _priority;
};

start:创建并启动线程

    void start() {
        if (_thread_num <= 0) {
            return;
        }
        size_t total = _thread_num - _thread_group.size();
        for (size_t i = 0; i < total; ++i) {
            _thread_group.create_thread(std::bind(&ThreadPool::run, this));
        }
    }

线程组中创建指定数量的线程,当线程组中线程数不足时,补齐缺少的。已经达指定数量时,该接口什么也不做。

等下我们再来看ThreadPool::run是个什么东西。

wait-等待线程组中所有线程退出


    void wait() {
        _thread_group.join_all();
    }

shutdown-队列中所有任务执行完成后让线程退出

   void shutdown() {
        _queue.push_exit(_thread_num);
    }

async-异步执行任务

如果运行同步执行,并且当前调用线程在线程组中,则同步执行任务。否则就放入队列中异步执行

	using TaskIn = std::function<void()>;
	using Ptr = std::shared_ptr<TaskCancelableImp>;
	    
    Task::Ptr async(TaskIn task, bool may_sync = true) override {
        if (may_sync && _thread_group.is_this_thread_in()) {
            task();
            return nullptr;
        }
        auto ret = std::make_shared<Task>(std::move(task));
        _queue.push_task(ret);
        return ret;
    }

async_first

与async的区别是,async将任务放在队尾,async-first将任务放在队首,确保优先执行。

    Task::Ptr async_first(TaskIn task, bool may_sync = true) override {
        if (may_sync && _thread_group.is_this_thread_in()) {
            task();
            return nullptr;
        }

        auto ret = std::make_shared<Task>(std::move(task));
        _queue.push_task_first(ret);
        return ret;
    }

size:有多少个任务待执行

   size_t size() {
        return _queue.size();
    }

shutdown:队列中所有任务执行完成后让线程退出

  void shutdown() {
        _queue.push_exit(_thread_num);
    }

队列的push_task和push_task_first会插入任务并触发一次唤醒wait的操作,等待在队列上的线程此时会从队列中获取到任务并执行。

但是push_exit没有给队列插入任务,也会触发其参数指定的n次唤醒wait的操作,等待在队列上的线程被唤醒后,因为实际并没有插入任务,所以这n次是获取不到任务的,队列为空。

基于上述条件,实现了run函数的自动退出(获取任务失败时,退出线程),push_exit指定多唤醒的次数与线程组中线程数量一致,每唤醒一次,就有一个线程被退出,最终刚好让所有线程都退出。

调用shutdown之后,需要调用wait()函数等待线程全部退出。如析构函数中所示

析构函数

    ~ThreadPool() {
        shutdown();
        wait();
    }

构造函数

  • _thread_num :线程池中最多多少个线程
  • _priority :线程优先级
  • auto_run :必要的话,自动开启线程池
  ThreadPool(int num = 1, Priority priority = PRIORITY_HIGHEST, bool auto_run = true) {
        _thread_num = num;
        _priority = priority;
        if (auto_run) {
            start();
        }
    }

run

  1. ThreadPool::setPriority(_priority):设置当前函数,也就是 run()在系统中的优先级。具体稍后讲
  2. 然后就进入了一个循环,循环中做了如下事情:
    • 不断从任务队列中获取任务,并执行
    • 如果任务队列为空了,就结束 ThreadPool::run
   void run() {
        ThreadPool::setPriority(_priority);
        Task::Ptr task;
        while (true) {
            startSleep();   // ThreadLoadCounter::startSleep()
            if (!_queue.get_task(task)) {  //TaskQueue::get_task
                //空任务,退出线程
                break;
            }
            sleepWakeUp();   //ThreadLoadCounter::sleepWakeUp()
            try {
                (*task)();  // 执行任务
                task = nullptr;
            } catch (std::exception &ex) {
                ErrorL << "ThreadPool执行任务捕获到异常:" << ex.what();
            }
        }
    }

setPriority

  static bool setPriority(Priority priority = PRIORITY_NORMAL, std::thread::native_handle_type threadId = 0) {
        static int Min = sched_get_priority_min(SCHED_OTHER);
        if (Min == -1) {
            return false;
        }
        static int Max = sched_get_priority_max(SCHED_OTHER);
        if (Max == -1) {
            return false;
        }
        static int Priorities[] = {Min, Min + (Max - Min) / 4, Min + (Max - Min) / 2, Min + (Max - Min) * 3 / 4, Max};

        if (threadId == 0) {
            threadId = pthread_self();
        }
        struct sched_param params;
        params.sched_priority = Priorities[priority];
        return pthread_setschedparam(threadId, SCHED_OTHER, &params) == 0;
    }

pthread_setschedparam(threadId, SCHED_OTHER, &params) 实现

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值