muduo库阅读(29)——Net部分:Reactor(EventLoop事件循环)
来源:互联网 发布:电影下载 知乎 编辑:程序博客网 时间:2024/05/17 23:20
Reactor是整个框架最核心的部分
它创建轮询器(Poller),创建用于传递消息的管道,初始化各个部分,然后进入一个无限循环,每一次循环中调用轮询器的轮询函数(等待函数),等待事件发生,如果有事件发生,就依次调用套接字(或其他的文件描述符)的事件处理器处理各个事件,然后调用投递的回调函数;接着进入下一次循环。
/* * 事件循环,即Reactor,一个线程最多一个Reactor * 这是一个接口类 */namespace muduo{namespace net{class Channel;class Poller;class TimerQueue;////// Reactor, at most one per thread.////// This is an interface class, so don't expose too much details.class EventLoop : boost::noncopyable{public:typedef boost::function<void()> Functor;EventLoop();~EventLoop(); // force out-line dtor, for scoped_ptr members.// 事件循环,必须在同一个线程内创建Reactor对象和调用它的loop函数void loop();/// better to call through shared_ptr<EventLoop> for 100% safety.// 跳出事件循环void quit();// 轮询返回的时间戳,通常表示有数据到来(即有事件到来)Timestamp pollReturnTime() const { return pollReturnTime_; }int64_t iteration() const { return iteration_; }/// Runs callback immediately in the loop thread./// It wakes up the loop, and run the cb./// If in the same loop thread, cb is run within the function./// Safe to call from other threads./* * 在事件循环中周期性的调用回调函数 */void runInLoop(const Functor& cb);/// Queues callback in the loop thread./// Runs after finish pooling./// Safe to call from other threads.// 把回调函数放在队列中,在轮询结束之后调用void queueInLoop(const Functor& cb);#ifdef __GXX_EXPERIMENTAL_CXX0X__void runInLoop(Functor&& cb);void queueInLoop(Functor&& cb);#endif// 在指定的时间调用回调函数TimerId runAt(const Timestamp& time, const TimerCallback& cb);// 在delay妙之后调用回调函数TimerId runAfter(double delay, const TimerCallback& cb);// 每隔interval妙调用一次回调函数TimerId runEvery(double interval, const TimerCallback& cb);// 取消一个计时器void cancel(TimerId timerId);#ifdef __GXX_EXPERIMENTAL_CXX0X__TimerId runAt(const Timestamp& time, TimerCallback&& cb);TimerId runAfter(double delay, TimerCallback&& cb);TimerId runEvery(double interval, TimerCallback&& cb);#endif/* * 下面的函数作为内部使用 */// internal usage// 唤醒void wakeup();// 更新事件处理器void updateChannel(Channel* channel);// 移除事件处理器void removeChannel(Channel* channel);// 是否有某一个事件处理器bool hasChannel(Channel* channel);// 断言自己是否在循环线程中void assertInLoopThread(){if (!isInLoopThread()){abortNotInLoopThread();}}// 是否在循环线程中bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }// 是否正在处理事件bool eventHandling() const { return eventHandling_; }// 设置上下文void setContext(const boost::any& context){ context_ = context; }// 返回上下文const boost::any& getContext() const{ return context_; }// 返回可修改的上下文boost::any* getMutableContext(){ return &context_; }// 返回当前线程的Reactor对象static EventLoop* getEventLoopOfCurrentThread();private:// 如果创建Reactor的线程和运行Reactor的线程不同就退出进程void abortNotInLoopThread();// 处理读读事件void handleRead(); // waked up// 执行投递的回调函数void doPendingFunctors();void printActiveChannels() const; // DEBUG// 事件处理器列表typedef std::vector<Channel*> ChannelList;// 是否正在循环中bool looping_; /* atomic */// 是否退出循环bool quit_; /* atomic and shared between threads, okay on x86, I guess. */// 是否正在处理事件bool eventHandling_; /* atomic */// 是否正在调用投递的回调函数bool callingPendingFunctors_; /* atomic */// 迭代器int64_t iteration_;// 线程idconst pid_t threadId_;// 轮询返回的时间Timestamp pollReturnTime_;// 轮询器boost::scoped_ptr<Poller> poller_;// 定时器队列boost::scoped_ptr<TimerQueue> timerQueue_;// 用于唤醒的描述符(将Reactor从等待中唤醒,一般是由于调用轮询器的等待函数而造成的阻塞)int wakeupFd_;// unlike in TimerQueue, which is an internal class,// we don't expose Channel to client.// 唤醒事件的处理器boost::scoped_ptr<Channel> wakeupChannel_;// 上下文boost::any context_;// scratch variables// 已激活的事件处理器队列ChannelList activeChannels_;// 当前正在调用的事件处理器Channel* currentActiveChannel_;// 投递的回调函数列表MutexLock mutex_;std::vector<Functor> pendingFunctors_; // @GuardedBy mutex_};}}
using namespace muduo;using namespace muduo::net;namespace{// 加上了__thread修饰符,表示每个线程都有一个指向Reactor的指针__thread EventLoop* t_loopInThisThread = 0;// 轮询的超时时间(10000毫秒 = 10妙)const int kPollTimeMs = 10000;/* * 创建管道,用于支持线程之间的通信 */int createEventfd(){int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);if (evtfd < 0){LOG_SYSERR << "Failed in eventfd";abort();}return evtfd;}#pragma GCC diagnostic ignored "-Wold-style-cast"/* * 这个类的作用是忽略管道事件 * 因为管道已经被使用另外的方法处理了 */class IgnoreSigPipe{public:IgnoreSigPipe(){::signal(SIGPIPE, SIG_IGN);// LOG_TRACE << "Ignore SIGPIPE";}};#pragma GCC diagnostic error "-Wold-style-cast"// 一个全局变量,用于实现对SIGPIPE信号的忽略IgnoreSigPipe initObj;}/* * 返回当前线程的Reactor对象的指针 */EventLoop* EventLoop::getEventLoopOfCurrentThread(){return t_loopInThisThread;}/* * Reactor的构造函数 */EventLoop::EventLoop(): looping_(false), quit_(false), eventHandling_(false), callingPendingFunctors_(false), iteration_(0), threadId_(CurrentThread::tid()), poller_(Poller::newDefaultPoller(this)), // 调用默认的轮询器来创建轮询 timerQueue_(new TimerQueue(this)), wakeupFd_(createEventfd()), wakeupChannel_(new Channel(this, wakeupFd_)), currentActiveChannel_(NULL){LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_;if (t_loopInThisThread){LOG_FATAL << "Another EventLoop " << t_loopInThisThread<< " exists in this thread " << threadId_;}else{t_loopInThisThread = this;}// 设置唤醒处理器的读回调函数为handleReadwakeupChannel_->setReadCallback(boost::bind(&EventLoop::handleRead, this));// we are always reading the wakeupfd// 启用读功能wakeupChannel_->enableReading();}/* * 析构函数,销毁对象并清理 */EventLoop::~EventLoop(){LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_<< " destructs in thread " << CurrentThread::tid();wakeupChannel_->disableAll();wakeupChannel_->remove();::close(wakeupFd_);t_loopInThisThread = NULL;}/* * Reactor的循环 */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 (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;}/* * 让Reactor退出循环 * 因为调用quit的线程和执行Reactor循环的线程不一定相同,如果他们不是同一个线程, * 那么必须使用wakeup函数让wakeupChannel_被激活,然后轮询函数返回,就可以处理事件,然后进入下一个循环, * 由于quit_已经被设置为true,所以就会跳出循环 */void EventLoop::quit(){quit_ = true;// There is a chance that loop() just executes while(!quit_) and exists,// then EventLoop destructs, then we are accessing an invalid object.// Can be fixed using mutex_ in both places.if (!isInLoopThread()){// 不知道为什么线程不同才会调用wakeup????同一个线程之内难道不可以调用?wakeup();}}// 运行一个回调函数void EventLoop::runInLoop(const Functor& cb){if (isInLoopThread()){cb();}else{// 如果不是同一个线程,那么将他添加到投递回调函数队列中queueInLoop(cb);}}// 把一个回调函数添加到投递回调函数队列中,并唤醒Reactorvoid EventLoop::queueInLoop(const Functor& cb){{MutexLockGuard lock(mutex_);pendingFunctors_.push_back(cb);}if (!isInLoopThread() || callingPendingFunctors_){wakeup();}}// 添加定时器事件:在某个时间点执行TimerId EventLoop::runAt(const Timestamp& time, const TimerCallback& cb){return timerQueue_->addTimer(cb, time, 0.0);}// 添加定时器事件:在delay妙之后执行TimerId EventLoop::runAfter(double delay, const TimerCallback& cb){Timestamp time(addTime(Timestamp::now(), delay));return runAt(time, cb);}// 添加定时器事件:每interval妙执行一次TimerId EventLoop::runEvery(double interval, const TimerCallback& cb){Timestamp time(addTime(Timestamp::now(), interval));return timerQueue_->addTimer(cb, time, interval);}#ifdef __GXX_EXPERIMENTAL_CXX0X__// FIXME: remove duplicationvoid EventLoop::runInLoop(Functor&& cb){if (isInLoopThread()){cb();}else{queueInLoop(std::move(cb));}}void EventLoop::queueInLoop(Functor&& cb){{MutexLockGuard lock(mutex_);pendingFunctors_.push_back(std::move(cb)); // emplace_back}if (!isInLoopThread() || callingPendingFunctors_){wakeup();}}TimerId EventLoop::runAt(const Timestamp& time, TimerCallback&& cb){return timerQueue_->addTimer(std::move(cb), time, 0.0);}TimerId EventLoop::runAfter(double delay, TimerCallback&& cb){Timestamp time(addTime(Timestamp::now(), delay));return runAt(time, std::move(cb));}TimerId EventLoop::runEvery(double interval, TimerCallback&& cb){Timestamp time(addTime(Timestamp::now(), interval));return timerQueue_->addTimer(std::move(cb), time, interval);}#endif// 取消一个计时器(定时器)void EventLoop::cancel(TimerId timerId){return timerQueue_->cancel(timerId);}// 更新事件处理器void EventLoop::updateChannel(Channel* channel){assert(channel->ownerLoop() == this);assertInLoopThread();poller_->updateChannel(channel);}// 移除一个事件处理器void EventLoop::removeChannel(Channel* channel){assert(channel->ownerLoop() == this);assertInLoopThread();if (eventHandling_){assert(currentActiveChannel_ == channel ||std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());}poller_->removeChannel(channel);}// 判断轮询器是否有事件处理器bool EventLoop::hasChannel(Channel* channel){assert(channel->ownerLoop() == this);assertInLoopThread();return poller_->hasChannel(channel);}// 退出进程void EventLoop::abortNotInLoopThread(){LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this<< " was created in threadId_ = " << threadId_<< ", current thread id = " << CurrentThread::tid();}/* * 唤醒 * 其实就是告诉正在处理循环的Reactor,发生了某一件事 */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";}}/* * 被wakeupChannel_使用 * wakeupChannel_有事件发生时候(wakeup一旦被调用,wakeupChannel_就被激活),就会执行handleEvent * 而handleEvent内部就会调用处理读的回调函数,wakeupChannel_的读回调函数就是handleRead */void EventLoop::handleRead(){uint64_t one = 1;ssize_t n = sockets::read(wakeupFd_, &one, sizeof one);if (n != sizeof one){LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8";}}// 执行投递的回调函数(投递的回调函数是在一次循环中,所有的事件都处理完毕之后才调用的)void EventLoop::doPendingFunctors(){std::vector<Functor> functors;callingPendingFunctors_ = true;{// 交换的目的是让pendingFunctors_继续存放投递的回调函数// 而functors则专门用于执行投递的回调函数// 这样就不会因为长期锁住pendingFunctors_而造成阻塞了MutexLockGuard lock(mutex_);functors.swap(pendingFunctors_);}for (size_t i = 0; i < functors.size(); ++i){functors[i]();}callingPendingFunctors_ = false;}// 打印已激活的事件处理器void EventLoop::printActiveChannels() const{for (ChannelList::const_iterator it = activeChannels_.begin();it != activeChannels_.end(); ++it){const Channel* ch = *it;LOG_TRACE << "{" << ch->reventsToString() << "} ";}}
0 0
- muduo库阅读(29)——Net部分:Reactor(EventLoop事件循环)
- muduo库阅读(35)——Net部分:用于执行事件循环(EventLoop)的线程类EventLoopThread
- muduo库阅读(36)——Net部分:事件循环线程池EventLoopThreadPool
- muduo网络库学习(四)事件驱动循环EventLoop
- muduo库阅读(30)——Net部分:事件处理器Channel
- Muduo网络库源码分析(一) EventLoop事件循环(Poller和Channel)
- Muduo网络库源码分析(一) EventLoop事件循环(Poller和Channel)
- muduo网络库学习之EventLoop(一):事件循环类图简介和muduo 定时器TimeQueue
- muduo库阅读(43)——Net部分:轮询器的epoll实现——EPollPoller
- muduo库阅读(31)——Net部分:定时器(计时器)Timer
- muduo库阅读(32)——Net部分:定时器(计时器)ID类TimerId
- muduo库阅读(23)——Net部分:应用层缓冲区类
- muduo库阅读(24)——Net部分:网络地址类
- muduo库阅读(25)——Net部分:服务器端的套接字类
- muduo库阅读(26)——Net部分:套接字常用操作的封装
- muduo库阅读(27)——Net部分:字节顺序转换的封装
- muduo库阅读(28)——Net部分:各类回调函数的定义
- muduo库阅读(33)——Net部分:定时器队列TimerQueue
- GPG入门教程
- 数据库封装Dbutil类
- tabBarItem设置背景色,标题
- ArcGIS 删除地理转换
- Android 客户端 TCP socket出现 android.os.NetworkOnMainThreadException
- muduo库阅读(29)——Net部分:Reactor(EventLoop事件循环)
- [原]在Windows中编译OpenH323(下)---------编译OpenH323
- 神经网络编程入门
- 关于时间的逻辑
- 实习整理(六)
- Qt继电器控制板代码
- android之 MAT、DDMS 等内存查看工具
- 根据传智播客ibatis视频教程编写的入门例子
- 欢迎使用CSDN-markdown编辑器