异步唤醒机制——muduo源码分析

之前一直不是很理解muduo里实现的异步回调,总算看懂了记录一下。

这是muduo最核心的事件循环:

void EventLoop::loop()
{
  assert(!looping_);
  assertInLoopThread();
  looping_ = true;
  quit_ = false;  // FIXME: what if someone calls quit() before loop() ?
  LOG_TRACE << "EventLoop " << this << " start looping";

  while (!quit_)
  {
    activeChannels_.clear();
    pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);//返回活跃事件
    ++iteration_;
    if (Logger::logLevel() <= Logger::TRACE)
    {
      printActiveChannels();
    }
    // TODO sort channel by priority
    eventHandling_ = true;
    for (Channel* channel : activeChannels_)//处理活跃时间
    {
      currentActiveChannel_ = channel;
      currentActiveChannel_->handleEvent(pollReturnTime_);
    }
    currentActiveChannel_ = NULL;
    eventHandling_ = false;
    doPendingFunctors(); //处理其他任务
  }

  LOG_TRACE << "EventLoop " << this << " stop looping";
  looping_ = false;
}

总的来说就是在while循环中做两件事情:
1、处理活跃的事件
2、处理其他任务


首先看看doPendingFunctors()

void EventLoop::doPendingFunctors()
{
  std::vector<Functor> functors;
  callingPendingFunctors_ = true;

  {
  MutexLockGuard lock(mutex_);
  functors.swap(pendingFunctors_);
  }

  for (const Functor& functor : functors)
  {
    functor();
  }
  callingPendingFunctors_ = false;
}

大概就是说弄了一个vector去接收任务,然后依次处理,我们来看看这个pendingFuncotrs_是哪来的:

void EventLoop::runInLoop(Functor cb)
{
  if (isInLoopThread())
  {
    cb();
  }
  else
  {
    queueInLoop(std::move(cb));
  }
}

如果有其他线程将任务放入了当前IO线程的runInLoop()中,那么就会执行queueInLoop()

void EventLoop::queueInLoop(Functor cb)
{
  {
  MutexLockGuard lock(mutex_);
  pendingFunctors_.push_back(std::move(cb));
  }

  if (!isInLoopThread() || callingPendingFunctors_)
  {
    wakeup();
  }
}

这个时候会把任务塞入pendingFunctors_中,如果!isInLoopThread() || callingPendingFunctors_,那么则调用wakeup()唤醒:

void EventLoop::wakeup()
{
  uint64_t one = 1;
  ssize_t n = sockets::write(wakeupFd_, &one, sizeof one);
  if (n != sizeof one)
  {
    LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8";
  }
}

也就是说满足条件!isInLoopThread() 或者callingPendingFunctors_的时候,会往wakeupFd_里面写数据:
第一个条件:可以理解为当前IO线程阻塞于返回活跃事件的poll()当中,需要往wakeupFd_里写东西,poll()会立即返回,从而返回活跃事件退出阻塞。

第二个条件:可以理解为当前IO线程正在执行这些额外任务。为了避免任务执行完后又阻塞在了poll()处,就让wakeupFd_可读,以免任务被延迟执行。


所谓异步唤醒就是解除阻塞状态。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值