《ZLToolKit源码学习笔记》(11)线程模块之工作线程池WorkThreadPool

 系列文章目录

《ZLToolKit源码学习笔记》(1)VS2019源码编译

《ZLToolKit源码学习笔记》(2)工具模块之日志功能分析

《ZLToolKit源码学习笔记》(3)工具模块之终端命令解析

《ZLToolKit源码学习笔记》(4)工具模块之消息广播器

《ZLToolKit源码学习笔记》(5)工具模块之资源池

《ZLToolKit源码学习笔记》(6)线程模块之整体框架概述

《ZLToolKit源码学习笔记》(7)线程模块之线程池组件:任务队列与线程组

《ZLToolKit源码学习笔记》(8)线程模块之线程负载计算器

《ZLToolKit源码学习笔记》(9)线程模块之任务执行器

《ZLToolKit源码学习笔记》(10)线程模块之线程池

《ZLToolKit源码学习笔记》(11)线程模块之工作线程池WorkThreadPool(本文)

《ZLToolKit源码学习笔记》(12)事件轮询模块之整体框架概述

《ZLToolKit源码学习笔记》(13)事件轮询模块之管道的简单封装

《ZLToolKit源码学习笔记》(14)事件轮询模块之定时器

《ZLToolKit源码学习笔记》(15)事件轮询模块之事件轮询器EventPoller

《ZLToolKit源码学习笔记》(16)网络模块之整体框架概述

《ZLToolKit源码学习笔记》(17)网络模块之基础接口封装类SockUtil

《ZLToolKit源码学习笔记》(18)网络模块之Buffer缓存

《ZLToolKit源码学习笔记》(19)网络模块之套接字封装

《ZLToolKit源码学习笔记》(20)网络模块之TcpServer

《ZLToolKit源码学习笔记》(21)网络模块之TcpClient与Session

《ZLToolKit源码学习笔记》(22)网络模块之UdpServer


前言

WorkThreadPool管理一组EventPoller事件轮询器线程,任务通过分配到不同的EventPoller来执行。


目录

系列文章目录

前言

一、概述

二、WorkThreadpool及其基类TaskExecutorGetterImp

2.1、TaskExecutorGetterImp

2.1.1、addPoller-创建一组EventPoller对象

2.1.2、getExecutorDelay-获取所有线程任务执行延时

2.1.3、getExecutor-获取负载最轻的任务执行器

2.2、WorkThreadPool

 三、WorkThreadPool和ThreadPool的区别


一、概述

 上图中可以大致看出WorkThreadPool的继承关系:

WorkThreadPool继承自TaskExecutorGettImp,而TaskExecutorGettImp管理了一组EventPoller(继承自TaskExecutor),所以,工作线程池,实际上就是管理了一组EventPoller对象的类。

那为什么要叫线程池呢?我们可以看下EventPoller类的runLoop函数:

void EventPoller::runLoop(bool blocked,bool regist_self) {
    if (blocked) {
        /* epoll_wait或者select事件监听处理 */
    } else {
        _loop_thread = new thread(&EventPoller::runLoop, this, true, regist_self);
        _sem_run_started.wait();
    }
}

可以看到,runLoop函数中,开启了一个线程,所以,每一个EventPoller对象,实际上都持有一个线程。


二、WorkThreadpool及其基类TaskExecutorGetterImp

2.1、TaskExecutorGetterImp

TaskExecutorGetterImp管理一组EventPoller对象,实现了简单的负载均衡,每次添加任务时,可以通过getExecutor接口选择一个负载最小的EventPoller来执行该任务。

2.1.1、addPoller-创建一组EventPoller对象

size_t TaskExecutorGetterImp::addPoller(const string &name, size_t size, int priority, bool register_thread) {
    auto cpus = thread::hardware_concurrency();
    size = size > 0 ? size : cpus;
    for (size_t i = 0; i < size; ++i) {
        EventPoller::Ptr poller(new EventPoller((ThreadPool::Priority) priority));
        poller->runLoop(false, register_thread);
        auto full_name = name + " " + to_string(i);
        poller->async([i, cpus, full_name]() {
            setThreadName(full_name.data());
            setThreadAffinity(i % cpus);
        });
        _threads.emplace_back(std::move(poller));
    }
    return size;
}

该接口主要是创建EventPoller对象,根据用户指定的数量来创建,或者根据系统CPU核心数来创建。runLoop接口中会开启线程并监听事件。 

2.1.2、getExecutorDelay-获取所有线程任务执行延时

void TaskExecutorGetterImp::getExecutorDelay(const function<void(const vector<int> &)> &callback) {
    std::shared_ptr<vector<int> > delay_vec = std::make_shared<vector<int>>(_threads.size());
    shared_ptr<void> finished(nullptr, [callback, delay_vec](void *) {
        //此析构回调触发时,说明已执行完毕所有async任务
        callback((*delay_vec));
    });
    int index = 0;
    for (auto &th : _threads) {
        std::shared_ptr<Ticker> delay_ticker = std::make_shared<Ticker>();
        th->async([finished, delay_vec, index, delay_ticker]() {
            (*delay_vec)[index] = (int) delay_ticker->elapsedTime();
        }, false);
        ++index;
    }
}

通过async插入一个用来计时的任务,获取当执行到该任务时所等待的时间。每一个线程添加的任务都捕获了finished智能指针对象,引用计数增加,当所有任务执行完成后,finished引用计数减为0,执行其自定义的删除器,通过回调将所有线程的任务执行延时返回。

2.1.3、getExecutor-获取负载最轻的任务执行器

TaskExecutor::Ptr TaskExecutorGetterImp::getExecutor() {
    auto thread_pos = _thread_pos;
    if (thread_pos >= _threads.size()) {
        thread_pos = 0;
    }

    TaskExecutor::Ptr executor_min_load = _threads[thread_pos];
    auto min_load = executor_min_load->load();

    for (size_t i = 0; i < _threads.size(); ++i, ++thread_pos) {
        if (thread_pos >= _threads.size()) {
            thread_pos = 0;
        }

        auto th = _threads[thread_pos];
        auto load = th->load();

        if (load < min_load) {
            min_load = load;
            executor_min_load = th;
        }
        if (min_load == 0) {
            break;
        }
    }
    _thread_pos = thread_pos;
    return executor_min_load;
}

 遍历所有任务执行器,并找到负载最轻的将其返回。

2.2、WorkThreadPool

WorkThreadPool基本上都是使用的其基类TaskExecutorGetterImp提供的方法,在构造函数中,调用基类的addPoller接口创建并启动了"工作线程池"。

EventPoller::Ptr WorkThreadPool::getFirstPoller(){
    return dynamic_pointer_cast<EventPoller>(_threads.front());
}

EventPoller::Ptr WorkThreadPool::getPoller(){
    return dynamic_pointer_cast<EventPoller>(getExecutor());
}

WorkThreadPool::WorkThreadPool(){
    //最低优先级
    addPoller("work poller", s_pool_size, ThreadPool::PRIORITY_LOWEST, false);
}

void WorkThreadPool::setPoolSize(size_t size) {
    s_pool_size = size;
}

 三、WorkThreadPool和ThreadPool的区别

 ThreadPool的“线程池”是一组std::Thread线程对象,池中所有线程共同工作在同一个任务队列上,通过信号量以及锁竟态的争抢任务来执行。

WorkThreadPool的“线程池“是一组EventPoller对象,每一个EventPoller对象内部都启动了一个std::Thread线程,EventPoller是一个事件处理器,在线程中监听指定事件,当事件到来时执行该事件对应的处理回调,默认的EventPoller监听了一个管道事件,对应在管道上有一个任务队列,当添加任务到队列时,触发管道事件,接着从队列中获取任务并执行。也就是说,每一个EventPoller线程都有一个自己的任务队列,多个线程之间不存在竞争关系。并且,还可以根据每一个线程的负载情况,均衡的将任务添加到多个线程中。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Libevent是一个事件驱动的网络编程框架,而event.h是其核心头文件之一。该头文件定义了事件处理相关的结构体、函数和宏等内容。 下面是event.h中常用的一些定义和函数: ### 1.事件回调函数 ```c typedef void (*event_callback_fn)(evutil_socket_t fd, short events, void *arg); ``` 该类型定义了事件回调函数的原型,其中fd是事件所在的文件描述符,events是事件类型,arg是用户传入的参数。 ### 2.事件结构体 ```c struct event { event_callback_fn ev_callback; // 事件回调函数 int ev_fd; // 事件所在的文件描述符 short ev_events; // 事件类型 short ev_res; // 事件结果 struct event_base *ev_base; // 事件所属的event_base void *ev_arg; // 用户传入的参数 }; ``` 该结构体表示一个事件,其中ev_callback是事件回调函数,ev_fd是事件所在的文件描述符,ev_events是事件类型,ev_res是事件结果,ev_base是事件所属的event_base,ev_arg是用户传入的参数。 ### 3.事件类型 ```c #define EV_TIMEOUT 0x01 #define EV_READ 0x02 #define EV_WRITE 0x04 #define EV_SIGNAL 0x08 #define EV_PERSIST 0x10 #define EV_ET 0x20 ``` 该宏定义了事件类型,分别为超时事件、读事件、写事件、信号事件、持续事件和边缘触发事件。 ### 4.事件处理函数 ```c struct event_base *event_base_new(void); int event_base_dispatch(struct event_base *base); int event_base_loopexit(struct event_base *base, const struct timeval *tv); void event_base_free(struct event_base *base); ``` 这些函数用于创建event_base、处理事件、退出事件循环和释放event_base等操作。 以上是event.h中的一些常用内容,更多细节可以查看源码和官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

秦时小

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

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

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

打赏作者

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

抵扣说明:

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

余额充值