EventPoller是整个ZLMediaKit中事件和线程调用的最核心的类,一般会有和cpu核心数量一致的线程数量,统一检测各种文件句柄或者网络句柄读写事件,定时器触发等
EventPollerPool,实现Singleton模式,通过instance 接口,在实际的构造函数中,创建 当前cpu核心数量的 EventPoller事件检测线程
class EventPollerPool : public std::enable_shared_from_this<EventPollerPool>, public TaskExecutorGetterImp {
public:
typedef std::shared_ptr<EventPollerPool> Ptr;
~EventPollerPool(){};
/**
* 获取单例
* @return
*/
static EventPollerPool &Instance();
/**
* 设置EventPoller个数,在EventPollerPool单例创建前有效
* 在不调用此方法的情况下,默认创建thread::hardware_concurrency()个EventPoller实例
* @param size EventPoller个数,如果为0则为thread::hardware_concurrency()
*/
static void setPoolSize(int size = 0);
/**
* 获取第一个实例
* @return
*/
EventPoller::Ptr getFirstPoller();
/**
* 根据负载情况获取轻负载的实例
* 如果优先返回当前线程,那么会返回当前线程
* 返回当前线程的目的是为了提高线程安全性
* @return
*/
EventPoller::Ptr getPoller();
/**
* 设置 getPoller() 是否优先返回当前线程
* 在批量创建Socket对象时,如果优先返回当前线程,
* 那么将导致负载不够均衡,所以可以暂时关闭然后再开启
* @param flag 是否优先返回当前线程
*/
void preferCurrentThread(bool flag = true);
private:
EventPollerPool() ;
private:
bool _preferCurrentThread = true;
};
EventPollerPool::EventPollerPool(){
auto size = s_pool_size > 0 ? s_pool_size : thread::hardware_concurrency();
//第一个参数是一个lambda函数,返回一个EventPoller::Ptr指针
createThreads([]() {
EventPoller::Ptr ret(new EventPoller);
ret->runLoop(false, true);
return ret;
}, size);
InfoL << "创建EventPoller个数:" << size;
}
/**
*
* @tparam FUN 任务执行器创建方式
* @param fun 任务执行器创建lambad
* @param threadnum 任务执行器个数,默认cpu核心数
*/
template <typename FUN>
void createThreads(FUN &&fun,int threadnum = thread::hardware_concurrency()){
for (int i = 0; i < threadnum; i++) {
//fun调用返回的是一个EventPoller::Ptr指针,这里直接转换为父类指针 TaskExecutor::Ptr
_threads.emplace_back(fun());
}
}
EventPoller的几个关键接口:
/**
* 添加事件监听
* @param fd 监听的文件描述符
* @param event 事件类型,例如 Event_Read | Event_Write
* @param eventCb 事件回调functional
* @return -1:失败,0:成功
*/
int addEvent(int fd, int event, PollEventCB eventCb);
/**
* 删除事件监听
* @param fd 监听的文件描述符
* @param delCb 删除成功回调functional
* @return -1:失败,0:成功
*/
int delEvent(int fd, PollDelCB delCb = nullptr);
/**
* 修改监听事件类型
* @param fd 监听的文件描述符
* @param event 事件类型,例如 Event_Read | Event_Write
* @return -1:失败,0:成功
*/
int modifyEvent(int fd, int event);
/**
* 异步执行任务
* @param task 任务
* @param may_sync 如果调用该函数的线程就是本对象的轮询线程,那么may_sync为true时就是同步执行任务
* @return 是否成功,一定会返回true
*/
Task::Ptr async(TaskIn task, bool may_sync = true) override ;
/**
* 同async方法,不过是把任务打入任务列队头,这样任务优先级最高
* @param task 任务
* @param may_sync 如果调用该函数的线程就是本对象的轮询线程,那么may_sync为true时就是同步执行任务
* @return 是否成功,一定会返回true
*/
Task::Ptr async_first(TaskIn task, bool may_sync = true) override ;
/**
* 判断执行该接口的线程是否为本对象的轮询线程
* @return 是否为本对象的轮询线程
*/
bool isCurrentThread();
/**
* 延时执行某个任务
* @param delayMS 延时毫秒数
* @param task 任务,返回值为0时代表不再重复任务,否则为下次执行延时,如果任务中抛异常,那么默认不重复任务
* @return 可取消的任务标签
*/
DelayTask::Ptr doDelayTask(uint64_t delayMS, function<uint64_t()> task);
/**
* 执行事件轮询
* @param blocked 是否用执行该接口的线程执行轮询
* @param regist_self 是否注册到全局map
*/
void runLoop(bool blocked , bool regist_self);