仿Muduo库实现高并发服务器——EventLoop模块

  金牌会员 | 2024-9-22 21:39:58 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 646|帖子 646|积分 1938

        我刚开始看这个模块时,也是看不明白,什么是事件管理模块。
        此时此刻,大向导的背影,还是那么清楚。联合故事模块,逐步理。
EventLoop模块 成员:


        绿色:

        利用智能指针对new出来的对象举行管理,这里就应该如许做,否则会内存泄露。
 
        蓝色:

        就是事件监控模块,一个EventLoop对象对应一个Poller对象,Poller负责文件形貌符的监控,大概有很多客户端的文件形貌符,定时管理文件形貌符,事件管理文件形貌符。在没其他文件形貌符。 
        灰色:

        就是定时任务模块,Connection模块调用 EventLoop模块共有接口,将定时任务插入到TimerWheel模块中。在这个项目中,定时器模块只是对客户发起的连接举行了管理(非活泼连接销毁功能)。

        赤色:

        就是EventLoop绑定的线程,线程函数是Start()死循环。
 
        绿色:就是EventLoop模块对任务池所做的通知机制,向任务池中插入任务时,会向事件管理文件形貌符中写入一个1。
        如果短时间内,有很多任务,但是事件管理文件形貌符来不及读取,就会不断对之前谁人数字加1,每插入一次就加一。但是将数字读取之后,并没有像TimerWheel模块中的,定时管理文件形貌符那样,用读取到的数字去实行定时任务。而是如许做。

        Poller模块 对文件形貌符举行事件监控,他是阻塞是期待,有事件就绪,处置惩罚就绪事件,哪怕只有一个事件。
        这里有两种情况:一,其他文件形貌符有就绪事件,但是任务池中也有事件,起首,将其他文件形貌符中就绪事件处置惩罚完,在处置惩罚任务池中的事件。 
        二,其他文件形貌符中没有就绪事件,但是任务池中有事件,这时间 事件管理文件形貌符就产生作用,他将Poller从,1,阻塞模式中叫醒,2去实行事件管理文件形貌符上的事件

3,再实行任务池中的任务。
任务池是怎样运行的

 
        起首创建一个新的任务池对象,将旧的任务池中的任务放到新的任务池中。如许做,不仅没有将下一次到来的任务 和这次要实行的任务搞混,还达到了运行任务的目的。 
线程安全题目:

        起首,线程安全就是只线程会修改进程中的一些资源,如果其他线程用到这个资源,就会产生,错误。由于这个资源被修改了。

        你想,主线程 将创建好的连接给子线程。这句话中就有两对象:主线程,子线程。
        以是我当时就没明白,为什么会有两个线程,由于没有掌握GDB调试,我就硬看和猜测。
我也扣问别人,别人提醒了一句,我才恍然大悟。下面就是我用打印呈现出来的征象。
 
         效果发现,客户端刚已连接,服务端就但因这句话,而且出现两个线程id。这就真是了我的猜想。你如果不明白,可以去打印。
        剩下的函数有关模块的讲过,这个模块单拿出来将,也就是明白话,没什么讲的。
EventLoop整体代码:

  1. class EventLoop {
  2.     private:
  3.         using Functor = std::function<void()>;
  4.         std::thread::id _thread_id;//线程ID
  5.         int _event_fd;//eventfd唤醒IO事件监控有可能导致的阻塞
  6.         std::unique_ptr<Channel> _event_channel;
  7.         Poller _poller;//进行所有描述符的事件监控
  8.         std::vector<Functor> _tasks;//任务池
  9.         std::mutex _mutex;//实现任务池操作的线程安全
  10.         TimerWheel _timer_wheel;//定时器模块
  11.     public:
  12.         //执行任务池中的所有任务
  13.         void RunAllTask() {
  14.             std::vector<Functor> functor;
  15.             {
  16.                 std::unique_lock<std::mutex> _lock(_mutex);
  17.                 _tasks.swap(functor);
  18.             }
  19.             for (auto &f : functor) {
  20.                 f();
  21.             }
  22.             return ;
  23.         }
  24.         static int CreateEventFd() {
  25.             int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
  26.             if (efd < 0) {
  27.                 ERR_LOG("CREATE EVENTFD FAILED!!");
  28.                 abort();//让程序异常退出
  29.             }
  30.             return efd;
  31.         }
  32.         void ReadEventfd() {
  33.             uint64_t res = 0;
  34.             int ret = read(_event_fd, &res, sizeof(res));
  35.             if (ret < 0) {
  36.                 //EINTR -- 被信号打断;   EAGAIN -- 表示无数据可读
  37.                 if (errno == EINTR || errno == EAGAIN) {
  38.                     return;
  39.                 }
  40.                 ERR_LOG("READ EVENTFD FAILED!");
  41.                 abort();
  42.             }
  43.             return ;
  44.         }
  45.         void WeakUpEventFd() {
  46.             uint64_t val = 1;
  47.             int ret = write(_event_fd, &val, sizeof(val));
  48.             if (ret < 0) {
  49.                 if (errno == EINTR) {
  50.                     return;
  51.                 }
  52.                 ERR_LOG("READ EVENTFD FAILED!");
  53.                 abort();
  54.             }
  55.             return ;
  56.         }
  57.     public:
  58.         EventLoop():_thread_id(std::this_thread::get_id()),
  59.                     _event_fd(CreateEventFd()),
  60.                     _event_channel(new Channel(this, _event_fd)),
  61.                     _timer_wheel(this) {
  62.             //给eventfd添加可读事件回调函数,读取eventfd事件通知次数
  63.             _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd, this));
  64.             //启动eventfd的读事件监控
  65.             _event_channel->EnableRead();
  66.         }
  67.         //三步走--事件监控-》就绪事件处理-》执行任务
  68.         void Start() {
  69.             while(1) {
  70.                 //1. 事件监控,
  71.                 std::vector<Channel *> actives;
  72.                 _poller.Poll(&actives);
  73.                 //2. 事件处理。
  74.                 for (auto &channel : actives) {
  75.                     channel->HandleEvent();
  76.                 }
  77.                 //3. 执行任务
  78.                 RunAllTask();
  79.             }
  80.         }
  81.         //用于判断当前线程是否是EventLoop对应的线程;
  82.         bool IsInLoop() {
  83.             return (_thread_id == std::this_thread::get_id());
  84.         }
  85.         void AssertInLoop() {
  86.             assert(_thread_id == std::this_thread::get_id());
  87.         }
  88.         //判断将要执行的任务是否处于当前线程中,如果是则执行,不是则压入队列。
  89.         void RunInLoop(const Functor &cb) {
  90.             if (IsInLoop()) {
  91.                 return cb();
  92.             }
  93.             return QueueInLoop(cb);
  94.         }
  95.         //将操作压入任务池
  96.         void QueueInLoop(const Functor &cb) {
  97.             {
  98.                 std::unique_lock<std::mutex> _lock(_mutex);
  99.                 _tasks.push_back(cb);
  100.             }
  101.             //唤醒有可能因为没有事件就绪,而导致的epoll阻塞;
  102.             //其实就是给eventfd写入一个数据,eventfd就会触发可读事件
  103.             WeakUpEventFd();
  104.         }
  105.         //添加/修改描述符的事件监控
  106.         void UpdateEvent(Channel *channel) { return _poller.UpdateEvent(channel); }
  107.         //移除描述符的监控
  108.         void RemoveEvent(Channel *channel) { return _poller.RemoveEvent(channel); }
  109.         void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb) { return _timer_wheel.TimerAdd(id, delay, cb); }
  110.         void TimerRefresh(uint64_t id) { return _timer_wheel.TimerRefresh(id); }
  111.         void TimerCancel(uint64_t id) { return _timer_wheel.TimerCancel(id); }
  112.         bool HasTimer(uint64_t id) { return _timer_wheel.HasTimer(id); }
  113. };
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表