当前位置: 首页 > wzjs >正文

店面设计费计入什么科目江门百度seo公司

店面设计费计入什么科目,江门百度seo公司,万网网站制作,国内外建筑设计网站目录 设计思路 类的设计 模块实现 私有接口 公有接口 疑惑点 设计思路 poller 模块的意义主要体现在它对 epoll 进行了更高层次的封装,让开发者在监控文件描述符(比如 socket)的事件时,操作变得更简单、更直观。咱们可以从…

目录

设计思路

类的设计

模块实现

私有接口

公有接口

疑惑点


设计思路

poller 模块的意义主要体现在它对 epoll 进行了更高层次的封装,让开发者在监控文件描述符(比如 socket)的事件时,操作变得更简单、更直观。咱们可以从几个方面来看看它的价值:

简化复杂性
原生的 epoll 是 Linux 提供的一种高效 I/O 事件通知机制,但它的 API 使用起来稍微有点繁琐,比如需要手动创建 epoll 实例、注册事件、处理就绪事件等。poller 模块把这些底层操作封装成了更友好的接口,让你不用直接跟 epoll_ctl、epoll_wait 这些函数打交道,减少了出错的机会。
提高代码可读性
通过 poller,你可以更专注于业务逻辑,而不是陷入底层的事件管理细节。比如,注册一个描述符、指定关心的事件(比如可读、可写),poller 通常会提供简洁的方法,代码看起来更清晰,维护起来也更容易。
统一抽象
如果你的项目需要在不同平台上运行(比如 Linux 用 epoll,其他系统可能用 select 或 poll),poller 可以作为一个抽象层,屏蔽底层的差异,让你用一套统一的接口来处理事件监控。这对跨平台开发超级友好!

1. 设计 Poller 的核心功能

  • 创建和管理 epoll 实例
  • 添加/修改/删除文件描述符及其关心的事件
  • 等待并返回就绪的事件
  • 提供简单的事件循环接口
  • 基于这些需求,可以设计一个 Poller 类或者结构体,封装这些功能。 

2. 基本封装思路

  • 初始化:调用 epoll_create 创建一个 epoll 实例。
  • 添加描述符:用 epoll_ctl 注册文件描述符和事件。
  • 事件等待:用 epoll_wait 获取就绪的事件。
  • 销毁:关闭 epoll 实例

对于epoll模型,要怎么封装呢?

我们知道,一个EventLoop线程也就是一个从属Reactor线程需要对应一个 epoll 模型,也就是一个 Poller对象(因为Poller就是对epoll的封装),那么这个对象中要实现事件的监控,就必须要保存一个epoll操作句柄(就是钥匙,没有这个钥匙,启动不了对应的epoll),也就是一个_epfd。

对于epoll模型来说,当使用epoll_ctl(),把文件描述符添加到红黑树模型上之后,当有事件就绪了,操作系统会去红黑树上找到该就绪事件对应的文件描述符_fd。然后会把这些_fd放在就绪队列上。而我们的Poller模块就是封装的epoll,所以肯定会获取到就绪的事件。那么这些事件就需要存储到一个就绪队列中。我们使用一个 struct epoll_event 类型的数组来模拟就绪队列。但是对于Poller的上层,也就是EventLoop来说,它并不需要得到一个 struct epoll_event 的数组,他其实只需要知道哪些Channel 中的事件就绪了,然后调用 Channel中的 HandlerEvent 方法去处理就绪事件就行了,所以我们未来设置就绪事件获取的时候,返回给外界或者说外界不需要传 struct epoll_event 数组,但是我们内部调用 epoll_wait 又必须使用这个数组,那么我们其实可以在Poller对象内部定义一个 struct epoll_event 数组便于后续使用。

同时,我们需要对Poller模型中监控的文件描述符以及对应的Channel对象进行管理,一个fd对应一个Channel对象。因为未来我们在添加某个事件的监控时,有可能该文件描述符在之前我们并没有添加到 epoll 模型中,这时候我们使用的是 EPOLL_CTL_ADD 操作,而其他的时候,对监控的事件进行修改,则是EPOLL_CTL_MOD操作,仅仅是对epoll模型中的红黑树节点中的内容进行修改,并不对节点的删除与插入做管理。 

就比如在一个城市中,epfd就好比不同的饭馆_fd就对应进入饭馆的顾客,当一个顾客来吃饭,就把该顾客对应的信息注册到记录本上(比如一对情侣坐在了A桌上),然后此时服务员(Poller)对已经注册的顾客进行监控,当_fd就绪了,这时候就需要通过Channel模块了,因为Poller模块只是监听fd,并且把就绪的fd放到就绪队列上。至于这些就绪的事件接下来要干什么是要传给Channel中的回调函数处理的。就好比A顾客离开了(就绪了Close事件),然后服务员检测到了A顾客就绪了离开的事件,他就会在对讲机里跟老板说,老板知道了是A顾客离开了也就是知道了A顾客所在桌的路线(Channel),就会调用调用回调函数(保洁),去执行打扫卫生的工作。如果Poller和Channel不联系起来,那老板知道有顾客离开了,但是不知道是哪个顾客离开了。

类的设计

我们需要一个私有的实际进行epoll模型操作的结构,也就是上面的 Update 接口,同时也需要一个辅助接口,也就是IsInPoller ,来判断某个Channel是否已经在Poller的监控中,来决定是使用 EPOLL_CTL_ADD还是使用EPOLL_CTL_MOD操作。

class Poller
{
private:
#define REVENTS_SIZE 1024 int _epfd;      //epoll模型的操作句柄std::unordered_map<int,Channel*> _channels;  //保存管理的套接字以及对应的Channelstruct epoll_event _revents[REVENTS_SIZE];  //用于从epoll模型中获取就绪的文件描述符及其就绪事件然后存储里面
private://判断该文件描述符是否在epoll模型中bool HasChannel(Channel* channel); //判断文件描述符是否登记到了Channel中void Update(Channel* channel,int op); 更新文件描述符的事件
public:             //提供的接口void UpdateEvents(Channel* channel); //添加/更新事件监控void Remove(Channel*channel); //删除事件监控size_t PollCtl(vector<Channel*> *active); //就绪事件放到"就绪队列"中
};

模块实现

私有接口

    bool HasChannel(Channel* channel) //判断文件描述符是否登记到了Channel中{return _channels.find(channel->Fd()) == _channels.end() ? false : true;}void Update(Channel* channel, int op) //更新文件描述符的事件{int fd = channel->Fd();struct epoll_event ev;ev.data.fd = fd;ev.events = channel->Events();int ret = epoll_ctl(_epfd, op, fd, &ev);if(ret < 0){ERR_LOG("epoll_ctl error");}return;}

公有接口

在公有接口中,有个函数 PollCtl 比较难理解,这里我给大家单独讲解一下。这个函数的目的是检测有哪些事件就绪(比如 socket 可读、可写),然后把对应的 Channel 塞进 actives 中,交给上层(比如 EventLoop)去处理类比epoll模型的就绪队列

    size_t PollCtl(vector<Channel*> *active)//就绪事件放到"就绪队列"中{int cnt = epoll_ctl(_epfd, _revents, REVENTS_SIZE, -1);//阻塞等待if(cnt < 0){if(errno = EINTR)ERR_LOG("epoll_wait failed");abort();}for(int i = 0; i <cnt; i++){auto it = _channels.find(_revents[i].data.fd);if(it == _channels.end()){ERR_LOG("find channel failed");abort();}it->second->SetRevents(_revents[i].events);active->push_back(it->second);}return cnt;}

完整公有接口

public:Poller(){_epfd = epoll_create(1);if(_epfd < 0){ERR_LOG("epoll_create error");abort(); //退出程序}}void UpdateEvents(Channel* channel)//添加/更新事件监控{if(HasChannel(channel))  //检查下是否已经在红黑树模型上{Update(Channel* channel, EPOLL_CTL_MOD);return;}_channels.insert(std::make_pair(channel->Fd(), channel)); //添加到红黑树模型上Update(channel, EPOLL_CTL_ADD);}size_t PollCtl(vector<Channel*> *active)//就绪事件放到"就绪队列"中{int cnt = epoll_ctl(_epfd, _revents, REVENTS_SIZE, -1);//阻塞等待if(cnt < 0){if(errno = EINTR)ERR_LOG("epoll_wait failed");abort();}for(int i = 0; i <cnt; i++){auto it = _channels.find(_revents[i].data.fd);if(it == _channels.end()){ERR_LOG("find channel failed");abort();}it->second->SetRevents(_revents[i].events);active->push_back(it->second);}return cnt;}void RemoveEvent(Channel* channel)//删除事件监控{auto it = _channels.find(channel->Fd());if(it ! = _channels.end()){_channels.erase(it);Update(channel, EPOLL_CTL_DEL);}}
};

目前来说,这段代码编译起来没什么问题,等后续我们实现完EventLoop模块再来进行联合调试。实现完EventLoop之后,我们的逻辑就大概清晰了。

疑惑点

std::unordered_map<int,Channel*> _channels;为啥需要这个

 那为啥map中的值不是Channel而是Channel*呢?

auto it = _channels.find(_revents[i].data.fd); 这个返回的是什么?这个it是个unorder_map?

active->push_back(it->second);这个是干嘛的,这个不是就绪队列吗,不是应该把就绪事件的文件描述符传给这个vector队列吗?怎么把channel*对象指针给填进去?

这个channel对象里面既有文件描述符也还有该文件描述符所对应的就绪事件,以及对应的回调函数

http://www.dtcms.com/wzjs/32744.html

相关文章:

  • app开发源码seo信息网
  • 北京市建设局网站首页b2b b2c c2c o2o区别
  • 自主建站百度推广自己怎么做
  • 网页的优化百度app优化
  • 做o2o平台网站需要多少钱如何创建一个个人网站
  • 网站个人备案类型软文广告经典案例100字
  • 网上做图赚钱的网站百度关键词查询
  • b站推广网站入口mmm2022最新版百度
  • 遵义市网站制作域名138查询网
  • 网站静态化的处理响应式网站 乐云seo品牌
  • 做的网站怎么让别人也能看到吗什么是精准营销
  • 公司网站制作专业公司优化推广
  • 数据做图网站有哪些优化公司网站
  • 哪家公司网站做的比较好快点tv下载安装
  • 做户外照明有哪些网站活动策划
  • 做时时彩测评网站怎么搭建属于自己的网站
  • 网站安全防护2345网址大全下载到桌面
  • 苏州做网站公司seo搜索引擎优化是做什么的
  • 网站建设自己在家接单微信朋友圈推广软文
  • dw做的网站如何发布百度收录网站多久
  • 电脑版网站建设seo收录查询工具
  • 如何做幼儿园网站设计seo顾问能赚钱吗
  • b2c平台网站百度推广售后服务电话
  • 深圳人大代表联络站网站建设黑帽seo联系方式
  • 厦门网站开发建设宁波网络优化seo
  • 聊天软件开发多少钱seo优化网站技术排名百度推广
  • 做名片模板网站中央新闻频道直播今天
  • 浙江省龙泉市建设局网站哪家培训机构好
  • 怎么做网站海报广告优化师的工作内容
  • 政府网站建设 领导重视百度搜索页