Event Loop

Reactor模式:

Reactor包含如下角色:

    • Handle 句柄;用来标识socket连接或是打开文件;
    • Synchronous Event Demultiplexer:同步事件多路分解器:由操作系统内核实现的一个函数;用于阻塞等待发生在句柄集合上的一个或多个事件;(如select/epoll;)
    • Event Handler:事件处理接口
    • Concrete Event HandlerA:实现应用程序所提供的特定事件处理逻辑;
    • Reactor:反应器,定义一个接口,实现以下功能:
      1)供应用程序注册和删除关注的事件句柄;
      2)运行事件循环;
      3)有就绪事件到来时,分发事件到之前注册的回调函数上处理;

业务流程及时序图:

  1. 应用启动,将关注的事件handle注册到Reactor中;
  2. 调用Reactor,进入无限事件循环,等待注册的事件到来;
  3. 事件到来,select返回,Reactor将事件分发到之前注册的回调函数中处理;

转自:https://segmentfault.com/a/1190000002715832

channel类:

  ///channel类的作用是把不同的IO事件分发给不同的回调函数,(一个fd上可以支持监听多个IO事件类型)
  ///每个channel对象只属于一个EventLoop
  ///每个channel对象只负责一个文件描述符fd的IO事件分发
  ///channel就像是一个容器,管理fd到callback的映射,当活动事件来临时,分发事件给不同的callback
  ///channel对象负责的fd
  const int  fd_;
  //channel关心的IO事件,有三种事件类型:kNoneEvent kReadEvent kWriteEvent,定义在channel.cc中,由enableReading disableReading enableWriting disableWriting等函数来设置
  int        events_;
  //目前活动的事件,由poller设置
  int        revents_; // it's the received event types of epoll or poll
//从shared_ptr对象obj构造weak_ptr tie_,获得资源的观测权
//防止shared_ptr出现循环引用
void Channel::tie(const boost::shared_ptr<void>& obj)
{
  tie_ = obj;
  tied_ = true;
}
//handleEvent是channel的核心,由EventLoop::loop()通过channel对象调用,然后该函数根据revents_的值分别调用不同的用户回调
void Channel::handleEvent(Timestamp receiveTime)
{
  boost::shared_ptr<void> guard;
  if (tied_)
  {
    //lock从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源
    guard = tie_.lock();
    if (guard)
    {
      handleEventWithGuard(receiveTime);
    }
  }
  else
  {
    handleEventWithGuard(receiveTime);
  }
}
//根据revents_的值(目前活动的事件)分别调用不同的用户回调,也就是说channel对象处理fd上各种类型的事件,与events_无关(?)
void Channel::handleEventWithGuard(Timestamp receiveTime)
{
  eventHandling_ = true;
  LOG_TRACE << reventsToString();
  if ((revents_ & POLLHUP) && !(revents_ & POLLIN))
  {
    if (logHup_)
    {
      LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";
    }
    if (closeCallback_) closeCallback_();
  }

  if (revents_ & POLLNVAL)
  {
    LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";
  }

  if (revents_ & (POLLERR | POLLNVAL))
  {
    if (errorCallback_) errorCallback_();
  }
  if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
  {
    if (readCallback_) readCallback_(receiveTime);
  }
  if (revents_ & POLLOUT)
  {
    if (writeCallback_) writeCallback_();
  }
  eventHandling_ = false;
}

poller类:

  ///fd到channel*的映射
  typedef std::map<int, Channel*> ChannelMap;
  ///每次fd被创建时,就应该加入到channels_中
  ChannelMap channels_;

poller类调用poll获得当前有活动IO事件的fd,将它对应的channel填入activeChannels.

EventLoop类:

//事件循环,该函数不能跨线程调用,只能在创建该对象的线程中调用
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();
    ///调用poll获得当前活动事件的channel列表(其实是将有活动事件的fd对应的channel填入activechannels_),然后依次调用每个channel的handleEvent函数
    pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
    ++iteration_;
    if (Logger::logLevel() <= Logger::TRACE)
    {
      printActiveChannels();
    }
    // TODO sort channel by priority
    eventHandling_ = true;
    for (ChannelList::iterator it = activeChannels_.begin();
        it != activeChannels_.end(); ++it)
    {
      currentActiveChannel_ = *it;
      currentActiveChannel_->handleEvent(pollReturnTime_);
    }
    currentActiveChannel_ = NULL;
    eventHandling_ = false;
//执行等待队列中的回调函数 doPendingFunctors(); } LOG_TRACE
<< "EventLoop " << this << " stop looping"; looping_ = false; }

 

//检查当前的线程是否是所在EventLoop对象所属的线程,因为有的函数是线程安全的,有的函数不是
bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } //保证线程安全地调用函数cb
void EventLoop::runInLoop(const Functor& cb) { ///当前线程与cb所属IO线程相同,回调会同步进行 if (isInLoopThread()) { cb(); } else { ///cb被加入队列,IO线程会被唤醒来调用这个函数
  
queueInLoop(cb); } } void EventLoop::queueInLoop(const Functor& cb) { { MutexLockGuard lock(mutex_); pendingFunctors_.push_back(cb); } //调用queueInLoop的线程不是IO线程或者IO线程正在调用doPendingFunctors,此时需要唤醒IO线程(指的是当前loop循环结束后,不要阻塞在poll循环处,而是立即从poll函数调用返回)
//调用queueInLoop的线程不是当前IO线程则需要唤醒当前线程,才能及时执行doPendingFunctors
//doPendingFunctors调用的Functor可能又添加了任务,故循环回去poll的时候需要被唤醒,进而继续执行doPendingFunctors(),否则这些新加的cb就不能被及时调用.若不唤醒,只有等监听的fd有活动事件的时候,才会继续执行
//只有在handleEvent()中调用queueInLoop不需要唤醒,因为接下来马上就会执行doPendingFunctors()
if (!isInLoopThread() || callingPendingFunctors_) { wakeup(); } }

 

//该函数只会被当前IO线程调用,依次执行队列中的函数
void EventLoop::doPendingFunctors()
{
  std::vector<Functor> functors;
  callingPendingFunctors_ = true;

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

  for (size_t i = 0; i < functors.size(); ++i)
  {
    functors[i]();
  }
  callingPendingFunctors_ = false;
}

IO线程平时阻塞在事件循环EventLoop::loop()的poll调用中,为了让IO线程能立刻执行用户回调,需要唤醒它。传统的方法是使用管道pipe,IO线程始终监视此管道的readable事件,在需要唤醒的时候,其他线程往管道里写一个字节,这样IO线程就从IO 多路复用阻塞调用中返回。linux中使用eventfd,可以更高效地唤醒,因为它不必管理缓冲区。

eventfd 是一个比 pipe 更高效的线程间事件通知机制,一方面它比 pipe 少用一个 file descripor,节省了资源;另一方面,eventfd 的缓冲区管理也简单得多,全部“buffer” 只有定长8 bytes,不像 pipe 那样可能有不定长的真正 buffer。

http://blog.csdn.net/solstice/article/details/6171831

//wakeupFd_是eventfd,
  int wakeupFd_;
  //wakeupChannel_处理wakeupFd上的readable事件,将事件分发至handleRead函数
  boost::scoped_ptr<Channel> wakeupChannel_;

 http://blog.csdn.net/NK_test/article/details/51138359

http://blog.csdn.net/yusiguyuan/article/details/40593721?utm_source=tuicool&utm_medium=referral

总结一下就是:
假设我们有这样的调用:loop->runInLoop(run),说明想让IO线程执行一定的计算任务,此时若是在当前的IO线程,就马上执行run();如果是其他线程调用的,那么就执行queueInLoop(run),将run异步添加到队列,当loop内处理完事件后,就执行doPendingFunctors(),也就执行到了run();最后想要结束线程的话,执行quit。

http://dirtysalt.info/muduo.html

EventLoopThread类:

IO线程不一定是主线程,我们可以在任何一个线程创建并运行EventLoop,一个程序也可以有不止一个IO线程.EventLoopThread会启动自己的线程,并在其中运行EventLoop:loop(),用条件变量来等待线程的创建和运行.

EventLoop* EventLoopThread::startLoop()
{
  assert(!thread_.started());
  thread_.start();

  {
    MutexLockGuard lock(mutex_);
    while (loop_ == NULL)
    {
      cond_.wait();
    }
  }

  return loop_;
}
//线程主函数
void EventLoopThread::threadFunc()
{
  EventLoop loop;

  if (callback_)
  {
    callback_(&loop);
  }

  {
    MutexLockGuard lock(mutex_);
    loop_ = &loop;
    //唤醒startLoop()
    cond_.notify();
  }

  loop.loop();
  //assert(exiting_);
  loop_ = NULL;
}

条件变量:http://blog.jobbole.com/44409/

 

 

http://blog.csdn.net/liuxuejiang158blog/article/details/16554023  这个例子要看一下

 

转载于:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/5647173.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值