27muduo_net库源码分析(三)

来源:互联网 发布:找数据 编辑:程序博客网 时间:2024/05/20 10:54

1.定时器函数选择

1.定时函数,用于让程序等待一段时间或安排计划任务:

sleep
alarm
usleep
nanosleep
clock_nanosleep
getitimer /setitimer
timer_create /timer_settime /timer_gettime /timer_delete
timerfd_create /timerfd_gettime /timerfd_settime

2.timerfd_* 入选的原因:

(1)sleep / alarm / usleep在实现时有可能用了信号SIGALRM,在多线程程序中处理信号是个相当麻烦的事情,应当尽量避免
(2)nanosleep 和 clock_nanosleep是线程安全的,但是在非阻塞网络编程中,绝对不能用让线程挂起的方式来等待一段时间,程序会失去响应。正确的做法是注册一个时间回调函数。
(3)getitimer 和 timer_create也是用信号来 deliver 超时,在多线程程序中也会有麻烦。
(4)timer_create可以指定信号的接收方是进程还是线程,算是一个进步,不过在信号处理函数(signal handler)能做的事情实在很受限。
(5)timerfd_create把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,这样就能很方便地融入到 select/poll 框架中,用统一的方式来处理 IO 事件和超时事件,这也正是 Reactor 模式的长处。

3.函数

#include <sys/timerfd.h>
inttimerfd_create(intclockid,int flags);
inttimerfd_settime(intfd,int flags, conststructitimerspec *new_value,structitimerspec *old_value);
inttimerfd_gettime(intfd,structitimerspec *curr_value)

2.代码

EPollPoller.h

// 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)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_EVENTLOOP_H#define MUDUO_NET_EVENTLOOP_H#include <vector>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>#include <muduo/base/CurrentThread.h>#include <muduo/base/Thread.h>#include <muduo/base/Timestamp.h>namespace muduo{namespace net{class Channel;class Poller;////// Reactor, at most one per thread.////// This is an interface class, so don't expose too much details.class EventLoop : boost::noncopyable{ public:  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_; }  // internal usage  void updateChannel(Channel* channel);// 在Poller中添加或者更新通道  void removeChannel(Channel* channel);// 从Poller中移除通道  void assertInLoopThread()  {    if (!isInLoopThread())    {      abortNotInLoopThread();    }  }  bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }  static EventLoop* getEventLoopOfCurrentThread(); private:  void abortNotInLoopThread();  void printActiveChannels() const; // DEBUG  typedef std::vector<Channel*> ChannelList;    bool looping_; /* atomic */  bool quit_; /* atomic */  bool eventHandling_; /* atomic */  const pid_t threadId_;// 当前对象所属线程ID  Timestamp pollReturnTime_;  boost::scoped_ptr<Poller> poller_;  ChannelList activeChannels_;// Poller返回的活动通道  Channel* currentActiveChannel_;// 当前正在处理的活动通道};}}#endif  // MUDUO_NET_EVENTLOOP_H

EPollPoller.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/poller/EPollPoller.h>#include <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <boost/static_assert.hpp>#include <assert.h>#include <errno.h>#include <poll.h>#include <sys/epoll.h>using namespace muduo;using namespace muduo::net;// On Linux, the constants of poll(2) and epoll(4)// are expected to be the same.BOOST_STATIC_ASSERT(EPOLLIN == POLLIN);BOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI);BOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT);BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP);BOOST_STATIC_ASSERT(EPOLLERR == POLLERR);BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP);namespace{const int kNew = -1;const int kAdded = 1;const int kDeleted = 2;}EPollPoller::EPollPoller(EventLoop* loop)  : Poller(loop),    epollfd_(::epoll_create1(EPOLL_CLOEXEC)),    events_(kInitEventListSize){  if (epollfd_ < 0)  {    LOG_SYSFATAL << "EPollPoller::EPollPoller";  }}EPollPoller::~EPollPoller(){  ::close(epollfd_);}Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels){  int numEvents = ::epoll_wait(epollfd_,                               &*events_.begin(),                               static_cast<int>(events_.size()),                               timeoutMs);  Timestamp now(Timestamp::now());  if (numEvents > 0)  {    LOG_TRACE << numEvents << " events happended";    fillActiveChannels(numEvents, activeChannels);    if (implicit_cast<size_t>(numEvents) == events_.size())    {      events_.resize(events_.size()*2);    }  }  else if (numEvents == 0)  {    LOG_TRACE << " nothing happended";  }  else  {    LOG_SYSERR << "EPollPoller::poll()";  }  return now;}void EPollPoller::fillActiveChannels(int numEvents,                                     ChannelList* activeChannels) const{  assert(implicit_cast<size_t>(numEvents) <= events_.size());  for (int i = 0; i < numEvents; ++i)  {    Channel* channel = static_cast<Channel*>(events_[i].data.ptr);#ifndef NDEBUG    int fd = channel->fd();    ChannelMap::const_iterator it = channels_.find(fd);    assert(it != channels_.end());    assert(it->second == channel);#endif    channel->set_revents(events_[i].events);    activeChannels->push_back(channel);  }}void EPollPoller::updateChannel(Channel* channel){  Poller::assertInLoopThread();  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();  const int index = channel->index();  if (index == kNew || index == kDeleted)  {    // a new one, add with EPOLL_CTL_ADD    int fd = channel->fd();    if (index == kNew)    {      assert(channels_.find(fd) == channels_.end());      channels_[fd] = channel;    }    else // index == kDeleted    {      assert(channels_.find(fd) != channels_.end());      assert(channels_[fd] == channel);    }    channel->set_index(kAdded);    update(EPOLL_CTL_ADD, channel);  }  else  {    // update existing one with EPOLL_CTL_MOD/DEL    int fd = channel->fd();    (void)fd;    assert(channels_.find(fd) != channels_.end());    assert(channels_[fd] == channel);    assert(index == kAdded);    if (channel->isNoneEvent())    {      update(EPOLL_CTL_DEL, channel);      channel->set_index(kDeleted);    }    else    {      update(EPOLL_CTL_MOD, channel);    }  }}void EPollPoller::removeChannel(Channel* channel){  Poller::assertInLoopThread();  int fd = channel->fd();  LOG_TRACE << "fd = " << fd;  assert(channels_.find(fd) != channels_.end());  assert(channels_[fd] == channel);  assert(channel->isNoneEvent());  int index = channel->index();  assert(index == kAdded || index == kDeleted);  size_t n = channels_.erase(fd);  (void)n;  assert(n == 1);  if (index == kAdded)  {    update(EPOLL_CTL_DEL, channel);  }  channel->set_index(kNew);}void EPollPoller::update(int operation, Channel* channel){  struct epoll_event event;  bzero(&event, sizeof event);  event.events = channel->events();  event.data.ptr = channel;  int fd = channel->fd();  if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)  {    if (operation == EPOLL_CTL_DEL)    {      LOG_SYSERR << "epoll_ctl op=" << operation << " fd=" << fd;    }    else    {      LOG_SYSFATAL << "epoll_ctl op=" << operation << " fd=" << fd;    }  }}

Reactor_test03.cc

#include <muduo/net/Channel.h>#include <muduo/net/EventLoop.h>#include <boost/bind.hpp>#include <stdio.h>#include <sys/timerfd.h>using namespace muduo;using namespace muduo::net;EventLoop* g_loop;int timerfd;void timeout(Timestamp receiveTime){printf("Timeout!\n");uint64_t howmany;::read(timerfd, &howmany, sizeof howmany);g_loop->quit();}int main(void){EventLoop loop;g_loop = &loop;timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);Channel channel(&loop, timerfd);channel.setReadCallback(boost::bind(timeout, _1));channel.enableReading();struct itimerspec howlong;bzero(&howlong, sizeof howlong);howlong.it_value.tv_sec = 1;::timerfd_settime(timerfd, 0, &howlong, NULL);loop.loop();::close(timerfd);}




原创粉丝点击