EventLoop分析[1-4]
来源:互联网 发布:ubuntu snmp配置 编辑:程序博客网 时间:2024/05/17 08:36
首先看看是如何调用的:
int main(int argc, char* argv[])
{
int numThreads = 0;
if (argc > 1)
{
benchmark = true;
Logger::setLogLevel(Logger::WARN);
numThreads = atoi(argv[1]);
}
EventLoop loop;
HttpServer server(&loop, InetAddress(8000), "dummy");
server.setHttpCallback(onRequest);
server.setThreadNum(numThreads);
server.start();
loop.loop();
}
主要看看EventLoop 的构造函数和EventLoop.loop()函数即可
EventLoop.h
#ifndef MUDUO_NET_EVENTLOOP_H
#define MUDUO_NET_EVENTLOOP_H
#include <vector>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
#include <muduo/base/Timestamp.h>
#include <muduo/net/Callbacks.h>
#include <muduo/net/TimerId.h>
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.
///
/// Loops forever.
///
/// Must be called in the same thread as creation of the object.
///
void loop();
void quit();
///
/// Time when poll returns, usually means data arrivial.
///
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);
// timers
///
/// Runs callback at 'time'.
/// Safe to call from other threads.
///
TimerId runAt(const Timestamp& time, const TimerCallback& cb);
///
/// Runs callback after @c delay seconds.
/// Safe to call from other threads.
///
TimerId runAfter(double delay, const TimerCallback& cb);
///
/// Runs callback every @c interval seconds.
/// Safe to call from other threads.
///
TimerId runEvery(double interval, const TimerCallback& cb);
///
/// Cancels the timer.
/// Safe to call from other threads.
///
void cancel(TimerId timerId);
// internal usage
void wakeup();
void updateChannel(Channel* channel);
void removeChannel(Channel* channel);
// pid_t threadId() const { return threadId_; }
void assertInLoopThread()
{
if (!isInLoopThread())
{
abortNotInLoopThread();
}
}
bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }
// bool callingPendingFunctors() const { return callingPendingFunctors_; }
bool eventHandling() const { return eventHandling_; }
static EventLoop* getEventLoopOfCurrentThread();
private:
void abortNotInLoopThread();
void handleRead(); // waked up
void doPendingFunctors();
void printActiveChannels() const; // DEBUG
typedef std::vector<Channel*> ChannelList;
bool looping_; /* atomic */
bool quit_; /* atomic */
bool eventHandling_; /* atomic */
bool callingPendingFunctors_; /* atomic */
int64_t iteration_;
const pid_t threadId_;
Timestamp pollReturnTime_;
boost::scoped_ptr<Poller> poller_;
boost::scoped_ptr<TimerQueue> timerQueue_;
int wakeupFd_;
// unlike in TimerQueue, which is an internal class,
// we don't expose Channel to client.
boost::scoped_ptr<Channel> wakeupChannel_;
ChannelList activeChannels_;
Channel* currentActiveChannel_;
MutexLock mutex_;
std::vector<Functor> pendingFunctors_; // @BuardedBy mutex_
};
}
}
#endif // MUDUO_NET_EVENTLOOP_H
EventLoop.cc
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include <muduo/net/EventLoop.h>
#include <muduo/base/Logging.h>
#include <muduo/base/Mutex.h>
#include <muduo/net/Channel.h>
#include <muduo/net/Poller.h>
#include <muduo/net/SocketsOps.h>
#include <muduo/net/TimerQueue.h>
#include <boost/bind.hpp>
#include <signal.h>
#include <sys/eventfd.h>
using namespace muduo;
using namespace muduo::net;
/*
仅限于本文件使用
IgnoreSigPipe() 当对端socket 关闭了,再write 时候进程默认是收到
SIGPIPE信号而终止,这里忽略此信号
createEventfd() 用于线程间通信的
*/
namespace
{
__thread EventLoop* t_loopInThisThread = 0;
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"
IgnoreSigPipe initObj;
}
EventLoop* EventLoop::getEventLoopOfCurrentThread()
{
return t_loopInThisThread;
}
/*
*/
EventLoop::EventLoop()
: looping_(false),
quit_(false),
eventHandling_(false),
callingPendingFunctors_(false),
iteration_(0),
threadId_(CurrentThread::tid()),
poller_(Poller::newDefaultPoller(this)),/*创建对象EPollPoller*/
timerQueue_(new TimerQueue(this)),
wakeupFd_(createEventfd()),
/*创建evtfd 并关联对应的Channel, 该对象里面设置读写及错误发生时候的回调函数*/
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;
}
/*给evtfd 设置读函数*/
wakeupChannel_->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();
::close(wakeupFd_);
t_loopInThisThread = NULL;
}
/*
*/
void EventLoop::loop()
{
assert(!looping_);
assertInLoopThread();
looping_ = true;
quit_ = false;
LOG_TRACE << "EventLoop " << this << " start looping";
while (!quit_)
{
/*
EPollPoller 类的poll 函数会收集所有发生事件的socketfd 的Channel
存于activeChannels_ 中;
这里的EventLoop::activeChannels_就是EPollPoller 类的poll 函数中用于填充的发生事件的socketfd的Channel
*/
activeChannels_.clear();
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
++iteration_;
if (Logger::logLevel() <= Logger::TRACE)
{
printActiveChannels();
}
/*
因为每一个socketfd 在对应的Channel 中会设置
读/写/及错误发生时候的回调函数的;
下面即是遍历收集到的activeChannels_ , 并执行每一个
Channel 的handleEvent 进而去调用设置的回调函数;
*/
eventHandling_ = true;
for (ChannelList::iterator it = activeChannels_.begin();
it != activeChannels_.end(); ++it)
{
currentActiveChannel_ = *it;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
/*
当别的类想异步执行某个函数时候
只需要调用EventLoop::runInLoop(const Functor& cb)
该函数里面会判断如果执行该函数的线程与主线程不同
则利用往evtfd 中写个字符触发epoll , 继而这里得到执行了,
即会执行上层注册的函数cb
*/
doPendingFunctors();
}
LOG_TRACE << "EventLoop " << this << " stop looping";
looping_ = false;
}
void EventLoop::quit()
{
quit_ = true;
if (!isInLoopThread())
{
wakeup();
}
}
void EventLoop::runInLoop(const Functor& cb)
{
if (isInLoopThread())
{
cb();
}
else
{
queueInLoop(cb);
}
}
void 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);
}
TimerId EventLoop::runAfter(double delay, const TimerCallback& cb)
{
Timestamp time(addTime(Timestamp::now(), delay));
return runAt(time, cb);
}
TimerId EventLoop::runEvery(double interval, const TimerCallback& cb)
{
Timestamp time(addTime(Timestamp::now(), interval));
return timerQueue_->addTimer(cb, time, interval);
}
void EventLoop::cancel(TimerId timerId)
{
return timerQueue_->cancel(timerId);
}
/*
调用EPollPoller 类的updateChannel
*/
void EventLoop::updateChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
poller_->updateChannel(channel);
}
/*
调用EPollPoller 类的removeChannel
*/
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);
}
void EventLoop::abortNotInLoopThread()
{
LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this
<< " was created in threadId_ = " << threadId_
<< ", current thread id = " << CurrentThread::tid();
}
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";
}
}
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;
{
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() << "} ";
}
}
总结:
EventLoop::loop会调用EPollPoller 类的poll函数将发生事件的socketfd的Channel存于EventLoop::activeChannels,接着loop函数中会去
执行EventLoop::activeChannels中每一个Channel的handleEvent函数,即会去执行注册给该socketfd的Channel的函数;还有就是用户通过envfd线程通信触发的epoll去执行用户的函数。
EventLoop::updateChannel(Channel* channel)会调用EPollPoller 类的updateChannel(channel);
EventLoop::removeChannel(Channel* channel)会调用EPollPoller 类的removeChannel(channel)
下来的问题?
监听套接字对应的Channel设置的回调函数在哪设置的,即监听套接字对应的Channel的建立地方;
客户连接套接字对应的Channel设置的回调函数在哪设置的,即客户连接套接对应的Channel的建立地方;
int main(int argc, char* argv[])
{
int numThreads = 0;
if (argc > 1)
{
benchmark = true;
Logger::setLogLevel(Logger::WARN);
numThreads = atoi(argv[1]);
}
EventLoop loop;
HttpServerserver(&loop, InetAddress(8000), "dummy");
server.setHttpCallback(onRequest);
server.setThreadNum(numThreads);
server.start(); //该函数会告诉我们答案的
loop.loop();
}
- EventLoop分析[1-4]
- squid源码分析1 ----EventLoop
- Netty EventLoop与EventExecutor分析(1)
- muduo::EventLoop分析
- 自顶向下深入分析Netty(四)--EventLoop-1
- muduo源码分析---EventLoop类
- muduo源码分析之EventLoop
- netty EventLoop 源码分析(一)
- EventLoop
- muduo源码分析--EventLoop 类的实现
- muduo源码分析之EventLoop::runInLoop()函数
- netty源码分析 之六 transport(EventLoop)
- Netty 源码分析之 EventLoop(一)
- Netty 源码分析之 EventLoop(二) (最重要)
- netty EventLoop write() 源码分析(二)
- Netty源码分析之EventLoop相关结构分析
- <二>---RIL层代码分析---RIL_startEventLoop()->eventLoop()->ril_event_loop()
- <二>---RIL层代码分析---RIL_startEventLoop()->eventLoop()->ril_event_loop()
- VS2008下Debug和Release的区别
- 教程七(对话框)
- 简单工厂模式
- 教程八(属性页表单和逃跑按钮)
- 将博客搬至CSDN
- EventLoop分析[1-4]
- 迭代器模式
- 数据泵导入导出数据库
- php手册
- 什么样的名字算得上是好名字
- [ios]iOS5 ARC学习笔记
- poj 2761 Feed the dogs 离线treap
- 解决两个网页传参中文乱码问题
- Android图片异步加载之Android-Universal-Image-Loader