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);}
阅读全文
1 0
- 27muduo_net库源码分析(三)
- EpollPoller --- muduo_net库源码分析(27)
- muduo_net库源码分析
- 25muduo_net库源码分析(一)
- 26muduo_net库源码分析(二)
- 28muduo_net库源码分析(四)
- 29muduo_net库源码分析(五)
- 30muduo_net库源码分析(六)
- 31muduo_net库源码分析(七)
- 32muduo_net库源码分析(八)
- 33muduo_net库源码分析(九)
- 34muduo_net库源码分析(十)
- muduo_net库源码分析(25)
- muduo_net库源码分析(25)
- muduo_net库源码分析(26-1
- 高并发服务器架构笔记(4)——muduo_net 源码分析
- 12muduo_base库源码分析(三)
- JUnit源码分析(三)
- junit
- PowerShell因为在此系统中禁止执行脚本问题的解决方法
- Java并发之CountDownLatch、CyclicBarrier和Semaphore
- 2017-8-23 股票总结
- Hexo发布带图片博客
- 27muduo_net库源码分析(三)
- Android Support v4,v7,v13的区别和应用场景
- 基于Spring4的Bean的装配和依赖注入
- 第三方登录QQ+获取QQ头像
- visual studio 2017 创建C项目工程
- 小白学tkinter之ttk
- 机器学习资料
- http协议
- 划分树入门