经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
muduo网络库学习笔记(三)TimerQueue定时器队列
来源:cnblogs  作者:艾露米婭娜  时间:2018/11/12 9:45:00  对本文有异议

目录

muduo网络库学习笔记(三)TimerQueue定时器队列


本章整理muduo中的TimerQueue,会简述关于timerfd系统定时函数的基本使用,和TimerQueue类的封装结构,最后给出TimerQueue::addTimer()接口的时序图与使用例子.

Linux中的时间函数

·time(2) / time_t(秒)
·ftime(3) / struct timeb(毫秒)
·gettimeofday(2) / struct timeval(微秒)
·clock_gettime(2) / struct timespec(纳秒)
还有gmtime / localtime / timegm / mktime / strftime / struct tm等与当
前时间无关的时间格式转换函数。
定时函数, 用于让程序等待一段时间或安排计划任务:·sleep(3)
·alarm(2)
·usleep(3)
·nanosleep(2)
·clock_nanosleep(2)
·getitimer(2) / setitimer(2)
·timer_create(2) / timer_settime(2) / timer_gettime(2) / timer_delete(2)
·timerfd_create(2) / timerfd_gettime(2) / timerfd_settime(2)

muduo中做的取舍如下
·(计时) 只使用gettimeofday(2)来获取当前时间。
·(定时) 只使用timerfd_*系列函数来处理定时任务。

gettimeofday(2)入选原因(这也是muduo::Timestamp class的主要设计考虑) :
1. time(2)的精度太低, ftime(3)已被废弃; clock_gettime(2)精度最高, 但是其系统调用的开销比gettimeofday(2)大。
2. 在x86-64平台上, gettimeofday(2)不是系统调用, 而是在用户态实现的, 没有上下文切换和陷入内核的开销32。
3. gettimeofday(2)的分辨率(resolution) 是1微秒, 现在的实现确实能达到这个计时精度, 足以满足日常计时的需要。 muduo::Timestamp用一个int64_t来表示从Unix Epoch到现在的微秒数, 其范围可达上下30万年。

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


timerfd简单使用介绍

本章使用到的两个系统函数:

  1. #include <sys/timerfd.h>
  2. int timerfd_create(int clockid, int flags);
  3. int timerfd_settime(int fd, int flags, const struct itimerspec *new_value,struct itimerspec *old_value);

1、timerfd_create函数生成一个定时器,返回与之关联的文件描述,其中的clockid可以设成CLOCK_REALTIME和CLOCK_MONOTONIC
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变
CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响

2、timerfd_settime用于启停定时器,new_value为超时时间,old_value为周期性定时时间,为0表示不进行周期性定时.

  1. struct timespec {
  2. time_t tv_sec; /* Seconds */
  3. long tv_nsec; /* Nanoseconds */
  4. };
  5. struct itimerspec {
  6. struct timespec it_interval; /* Interval for periodic timer */
  7. struct timespec it_value; /* Initial expiration */
  8. };

timerfd示例

通过select 监听timerfd,可读时表明到达定时时间.

  1. #include <sys/timerfd.h>
  2. #include <sys/select.h>
  3. /* According to earlier standards */
  4. #include <sys/time.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. int main()
  8. {
  9. int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK |TFD_CLOEXEC);
  10. struct itimerspec howlong;
  11. bzero(&howlong, sizeof howlong);
  12. howlong.it_value.tv_sec = 3;
  13. timerfd_settime(timerfd, 0, &howlong, NULL);
  14. fd_set rdset;
  15. FD_ZERO(&rdset);
  16. FD_SET(timerfd, &rdset);
  17. struct timeval timeout;
  18. timeout.tv_sec = 1;
  19. timeout.tv_usec = 0;
  20. while(1)
  21. {
  22. if(select(timerfd + 1, &rdset, NULL, NULL, &timeout) == 0)
  23. {
  24. std::cout << "timeout\n";
  25. timeout.tv_sec = 1;
  26. timeout.tv_usec = 0;
  27. FD_SET(timerfd, &rdset);
  28. continue;
  29. }
  30. std::cout << " timer happend\n";
  31. break;
  32. }
  33. close(timerfd);
  34. return 0;
  35. }
  36. /* print
  37. timeout
  38. timeout
  39. timer happend
  40. */

muduo中对timerfd的封装

  1. int createTimerfd()
  2. {
  3. int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
  4. TFD_NONBLOCK | TFD_CLOEXEC);
  5. if (timerfd < 0)
  6. {
  7. std::cout << "Failed in timerfd_create" << std::endl;
  8. abort();
  9. }
  10. return timerfd;
  11. }
  12. struct timespec howMuchTimeFromNow(TimeStamp when)
  13. {
  14. int64_t microseconds = when.microSecondsSinceEpoch()
  15. - TimeStamp::now().microSecondsSinceEpoch();
  16. if (microseconds < 100)
  17. {
  18. microseconds = 100;
  19. }
  20. struct timespec ts;
  21. ts.tv_sec = static_cast<time_t>(
  22. microseconds / TimeStamp::kMicroSecondsPerSecond);
  23. ts.tv_nsec = static_cast<long>(
  24. (microseconds % TimeStamp::kMicroSecondsPerSecond) * 1000);
  25. return ts;
  26. }
  27. void readTimerfd(int timerfd, TimeStamp now)
  28. {
  29. uint64_t howmany;
  30. ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
  31. std::cout << "TimerQueue::handleRead() " << howmany << " at " << now.toString() << std::endl;
  32. if (n != sizeof howmany)
  33. {
  34. std::cout << "TimerQueue::handleRead() reads " << n << " bytes instead of 8" << std::endl;
  35. }
  36. }
  37. void resetTimerfd(int timerfd, TimeStamp expiration)
  38. {
  39. // wake up loop by timerfd_settime()
  40. struct itimerspec newValue;
  41. struct itimerspec oldValue;
  42. bzero(&newValue, sizeof newValue);
  43. bzero(&oldValue, sizeof oldValue);
  44. newValue.it_value = howMuchTimeFromNow(expiration);
  45. int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
  46. if (ret)
  47. {
  48. std::cout << "timerfd_settime()" << std::endl;
  49. }
  50. }

TimerQueue的结构.

TimerQueue只提供了两个对外的接口
addTimer() 添加一个定时器超时执行回调函数cb. interval是周期性定时时间,本章不讲,置零不打开.
cancel() 取消一个定时器,本章也不细述,本章只介绍addTimer()接口.后面如果需要会补充本章.

TimerQueue定义如下

  1. class TimerQueue
  2. {
  3. public:
  4. TimerQueue(EventLoop* loop);
  5. ~TimerQueue();
  6. // Schedules the callback to be run at given time,
  7. TimerId addTimer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval = 0.0);
  8. void cancel(TimerId timerId);
  9. private:
  10. /*
  11. .....
  12. */
  13. EventLoop* p_loop;
  14. const int m_timerfd;
  15. Channel m_timerfdChannel;
  16. //Timer List sorted by expiration
  17. TimerList m_timers;
  18. ActiveTimerSet m_activeTimers;
  19. };

虽然只提供了两个对外接口,但是私有成比较复杂,首先简介成员Timer.

Timer

Timer类作为TimerQueue的内部成员使用,封装一个定时器,addTimer()接口调用后生成一个Timer(),外头的回调函数和定时反应时间会封装再此Timer中.
Tiemr主要接口都是获取这些构造时配置的成员值
run() 调用回调函数.
expiration 定时器过期时间.
interval 周期性定时时间.
repeat 是否是周期性定时.
sequence 一个静态成员,用于记录Timer创建的个数. 为了保证它的线程安全性,使用AtomicInt64封装了一层原子操作.

TimerId 用于Cancel Timer的标志Id, 这两个类都不复杂,可自行参看muduo源码,也可翻我github上的SimpleMuduo单独类文件夹下的测试代码.

  1. Timer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval)
  2. :m_callBack(cb),
  3. m_expiration(when),
  4. m_interval(interval),
  5. m_repeat(interval > 0.0),
  6. m_sequence(s_numCreated.incrementAndGet())
  1. TimerId TimerQueue::addTimer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval)
  2. {
  3. Timer* timer = new Timer(cb, when, interval);
  4. //p_loop->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer));
  5. return TimerId(timer, timer->sequence());
  6. }

Timer的容器.

  1. typedef std::pair<TimeStamp, Timer*> Entry;
  2. typedef std::set<Entry> TimerList;
  3. typedef std::pair<Timer*, int64_t> ActiveTimer;
  4. typedef std::set<ActiveTimer> ActiveTimerSet;

为了解决无法处理两个Timer到期时间相同的情况。使用了pair将时间戳和Timer的地址组成了一对.然后使用Set存储.
ActiveTimer 将Timer和sequence组成一对主要作用来索引迭代的.

TimerQueue私有接口介绍.

  1. void addTimerInLoop(Timer* timer);
  2. void cancelInLoop(TimerId timerId);
  3. //called when timerfd alarms
  4. void handleRead();
  5. //move out all expired timers and return they.
  6. std::vector<Entry> getExpired(TimeStamp now);
  7. bool insert(Timer* timer);
  8. void reset(const std::vector<Entry>& expired, TimeStamp now);

添加定时器

bool insert(Timer* timer); //插入一个定时器.

EventLoop添加了一个runInLoop接口: 在它的IO线程内执行某个用户
任务回调, 即EventLoop::runInLoop(const Functor& cb), 其中Functor是
std::function<void()>。 如果用户在当前IO线程调用这个函数, 回调会
同步进行; 如果用户在其他线程调用runInLoop(), cb会被加入队列, IO
线程会被唤醒来调用这个Functor。

addTimer()使用了EventLoop的runInLoop接口(这个接口主要来保证线程安全性的,暂不讲),来执行addTimerInLoop().addTimerInLoop()调用insert()插入定时器.
如果此定时器是最早触发的那一个则会调用resetTimerfd()->timerfd_settime()启动定时器.

addTimer()->addTimerInLoop()->insert()->resetTimerfd()->timerfd_settime()

更新定时器

添加逻辑就在上面了,下面给出处理逻辑.
三个接口.
void handleRead(); //定时器触发回调.获取已过期的事件并处理随后更新列表.
std::vector

handleRead()->getExpired()->Timer->run(cb)->reset()->resetTimerfd()->timerfd_settime()

时序图

TimerQueue源码

  1. #ifndef _NET_TIMERQUEUE_HH
  2. #define _NET_TIMERQUEUE_HH
  3. #include "TimerId.hh"
  4. #include "CallBacks.hh"
  5. #include "TimeStamp.hh"
  6. #include "Channel.hh"
  7. #include <set>
  8. #include <vector>
  9. class EventLoop;
  10. class TimerQueue
  11. {
  12. public:
  13. TimerQueue(EventLoop* loop);
  14. ~TimerQueue();
  15. // Schedules the callback to be run at given time,
  16. TimerId addTimer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval = 0.0);
  17. void cancel(TimerId timerId);
  18. private:
  19. typedef std::pair<TimeStamp, Timer*> Entry;
  20. typedef std::set<Entry> TimerList;
  21. typedef std::pair<Timer*, int64_t> ActiveTimer;
  22. typedef std::set<ActiveTimer> ActiveTimerSet;
  23. void addTimerInLoop(Timer* timer);
  24. void cancelInLoop(TimerId timerId);
  25. //called when timerfd alarms
  26. void handleRead();
  27. //move out all expired timers and return they.
  28. std::vector<Entry> getExpired(TimeStamp now);
  29. bool insert(Timer* timer);
  30. void reset(const std::vector<Entry>& expired, TimeStamp now);
  31. EventLoop* p_loop;
  32. const int m_timerfd;
  33. Channel m_timerfdChannel;
  34. //Timer List sorted by expiration
  35. TimerList m_timers;
  36. ActiveTimerSet m_activeTimers;
  37. bool m_callingExpiredTimers; /*atomic*/
  38. ActiveTimerSet m_cancelingTimers;
  39. };
  40. #endif
  41. //TimerQueeu.cpp
  42. #include <stdint.h>
  43. #include <assert.h>
  44. #include <sys/timerfd.h>
  45. #include <unistd.h>
  46. #include "Logger.hh"
  47. #include "EventLoop.hh"
  48. #include "Timer.hh"
  49. #include "TimerQueue.hh"
  50. namespace TimerFd
  51. {
  52. int createTimerfd()
  53. {
  54. int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
  55. TFD_NONBLOCK | TFD_CLOEXEC);
  56. if (timerfd < 0)
  57. {
  58. LOG_SYSFATAL << "Failed in timerfd_create";
  59. }
  60. return timerfd;
  61. }
  62. struct timespec howMuchTimeFromNow(TimeStamp when)
  63. {
  64. int64_t microseconds = when.microSecondsSinceEpoch()
  65. - TimeStamp::now().microSecondsSinceEpoch();
  66. if (microseconds < 100)
  67. {
  68. microseconds = 100;
  69. }
  70. struct timespec ts;
  71. ts.tv_sec = static_cast<time_t>(
  72. microseconds / TimeStamp::kMicroSecondsPerSecond);
  73. ts.tv_nsec = static_cast<long>(
  74. (microseconds % TimeStamp::kMicroSecondsPerSecond) * 1000);
  75. return ts;
  76. }
  77. void readTimerfd(int timerfd, TimeStamp now)
  78. {
  79. uint64_t howmany;
  80. ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
  81. LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
  82. if (n != sizeof howmany)
  83. {
  84. LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
  85. }
  86. }
  87. void resetTimerfd(int timerfd, TimeStamp expiration)
  88. {
  89. // wake up loop by timerfd_settime()
  90. LOG_TRACE << "resetTimerfd()";
  91. struct itimerspec newValue;
  92. struct itimerspec oldValue;
  93. bzero(&newValue, sizeof newValue);
  94. bzero(&oldValue, sizeof oldValue);
  95. newValue.it_value = howMuchTimeFromNow(expiration);
  96. int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
  97. if (ret)
  98. {
  99. LOG_SYSERR << "timerfd_settime()";
  100. }
  101. }
  102. };
  103. using namespace TimerFd;
  104. TimerQueue::TimerQueue(EventLoop* loop)
  105. :p_loop(loop),
  106. m_timerfd(createTimerfd()),
  107. m_timerfdChannel(p_loop, m_timerfd),
  108. m_timers(),
  109. m_callingExpiredTimers(false)
  110. {
  111. m_timerfdChannel.setReadCallBack(std::bind(&TimerQueue::handleRead, this));
  112. m_timerfdChannel.enableReading();
  113. }
  114. TimerQueue::~TimerQueue()
  115. {
  116. m_timerfdChannel.disableAll();
  117. m_timerfdChannel.remove();
  118. ::close(m_timerfd);
  119. for (TimerList::iterator it = m_timers.begin();
  120. it != m_timers.end(); ++it)
  121. {
  122. delete it->second;
  123. }
  124. }
  125. std::vector<TimerQueue::Entry> TimerQueue::getExpired(TimeStamp now)
  126. {
  127. std::vector<Entry> expired;
  128. Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>UINTPTR_MAX);
  129. TimerList::iterator it = m_timers.lower_bound(sentry);
  130. assert(it == m_timers.end() || now < it->first);
  131. std::copy(m_timers.begin(), it, back_inserter(expired));
  132. m_timers.erase(m_timers.begin(), it);
  133. for(std::vector<Entry>::iterator it = expired.begin();
  134. it != expired.end(); ++it)
  135. {
  136. ActiveTimer timer(it->second, it->second->sequence());
  137. size_t n = m_activeTimers.erase(timer);
  138. assert(n == 1); (void)n;
  139. }
  140. assert(m_timers.size() == m_activeTimers.size());
  141. return expired;
  142. }
  143. TimerId TimerQueue::addTimer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval)
  144. {
  145. Timer* timer = new Timer(cb, when, interval);
  146. p_loop->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer));
  147. return TimerId(timer, timer->sequence());
  148. }
  149. void TimerQueue::addTimerInLoop(Timer* timer)
  150. {
  151. p_loop->assertInLoopThread();
  152. bool earliestChanged = insert(timer);
  153. if (earliestChanged)
  154. {
  155. resetTimerfd(m_timerfd, timer->expiration());
  156. }
  157. }
  158. void TimerQueue::cancel(TimerId timerId)
  159. {
  160. p_loop->runInLoop(std::bind(&TimerQueue::cancelInLoop, this, timerId));
  161. }
  162. void TimerQueue::cancelInLoop(TimerId timerId)
  163. {
  164. p_loop->assertInLoopThread();
  165. assert(m_timers.size() == m_activeTimers.size());
  166. ActiveTimer timer(timerId.m_timer, timerId.m_sequence);
  167. ActiveTimerSet::iterator it = m_activeTimers.find(timer);
  168. if(it != m_activeTimers.end())
  169. {
  170. size_t n = m_timers.erase(Entry(it->first->expiration(), it->first));
  171. assert(n == 1);
  172. delete it->first;
  173. }
  174. else if (m_callingExpiredTimers)
  175. {
  176. m_cancelingTimers.insert(timer);
  177. }
  178. assert(m_timers.size() == m_activeTimers.size());
  179. }
  180. bool TimerQueue::insert(Timer* timer)
  181. {
  182. p_loop->assertInLoopThread();
  183. assert(m_timers.size() == m_activeTimers.size());
  184. bool earliestChanged = false;
  185. TimeStamp when = timer->expiration();
  186. TimerList::iterator it = m_timers.begin();
  187. if (it == m_timers.end() || when < it->first)
  188. {
  189. earliestChanged = true;
  190. }
  191. {
  192. std::pair<TimerList::iterator, bool> result
  193. = m_timers.insert(Entry(when, timer));
  194. assert(result.second); (void)result;
  195. }
  196. {
  197. std::pair<ActiveTimerSet::iterator, bool> result
  198. = m_activeTimers.insert(ActiveTimer(timer, timer->sequence()));
  199. assert(result.second); (void)result;
  200. }
  201. LOG_TRACE << "TimerQueue::insert() " << "m_timers.size() : "
  202. << m_timers.size() << " m_activeTimers.size() : " << m_activeTimers.size();
  203. assert(m_timers.size() == m_activeTimers.size());
  204. return earliestChanged;
  205. }
  206. void TimerQueue::handleRead()
  207. {
  208. p_loop->assertInLoopThread();
  209. TimeStamp now(TimeStamp::now());
  210. readTimerfd(m_timerfd, now);
  211. std::vector<Entry> expired = getExpired(now);
  212. LOG_TRACE << "Expired Timer size " << expired.size() << " ";
  213. m_callingExpiredTimers = true;
  214. m_cancelingTimers.clear();
  215. for(std::vector<Entry>::iterator it = expired.begin();
  216. it != expired.end(); ++it )
  217. {
  218. it->second->run();
  219. }
  220. m_callingExpiredTimers = false;
  221. reset(expired, now);
  222. }
  223. void TimerQueue::reset(const std::vector<Entry>& expired, TimeStamp now)
  224. {
  225. TimeStamp nextExpire;
  226. for(std::vector<Entry>::const_iterator it = expired.begin();
  227. it != expired.end(); ++it)
  228. {
  229. ActiveTimer timer(it->second, it->second->sequence());
  230. if(it->second->repeat()
  231. && m_cancelingTimers.find(timer) == m_cancelingTimers.end())
  232. {//如果是周期定时器则重新设定时间插入. 否则delete.
  233. it->second->restart(now);
  234. insert(it->second);
  235. }
  236. else
  237. {// FIXME move to a free list no delete please
  238. delete it->second;
  239. }
  240. }
  241. if (!m_timers.empty())
  242. {
  243. nextExpire = m_timers.begin()->second->expiration();
  244. }
  245. if (nextExpire.valid())
  246. {
  247. resetTimerfd(m_timerfd, nextExpire);
  248. }
  249. }

TimerQueue使用示例

测试TimerQueue的addTimer接口.

  1. #include <errno.h>
  2. #include <thread>
  3. #include <strings.h>
  4. #include <poll.h>
  5. #include <functional>
  6. #include "EventLoop.hh"
  7. #include "Channel.hh"
  8. #include "Poller.hh"
  9. #include "Logger.hh"
  10. #include "Timer.hh"
  11. #include "TimeStamp.hh"
  12. #include "TimerQueue.hh"
  13. EventLoop* g_loop;
  14. void print() { LOG_DEBUG << "test print()"; }
  15. void test()
  16. {
  17. LOG_DEBUG << "[test] : test timerQue";
  18. }
  19. int main()
  20. {
  21. EventLoop loop;
  22. g_loop = &loop;
  23. TimerQueue timerQue(&loop);
  24. timerQue.addTimer(test, times::addTime(TimeStamp::now(), 3.0));
  25. timerQue.addTimer(test, times::addTime(TimeStamp::now(), 3.0));
  26. timerQue.addTimer(test, times::addTime(TimeStamp::now(), 5.0));
  27. loop.loop();
  28. return 0;
  29. }
  1. ./test.out
  2. 2018-11-11 15:49:22.493990 [TRACE] [Poller.cpp:64] [updateChannel] fd= 3 events3
  3. 2018-11-11 15:49:22.494042 [TRACE] [EventLoop.cpp:34] [EventLoop] EventLoop Create 0x7FFFBD3C39B0 in thread 3262
  4. 2018-11-11 15:49:22.494047 [TRACE] [Poller.cpp:64] [updateChannel] fd= 5 events3
  5. 2018-11-11 15:49:22.494055 [TRACE] [TimerQueue.cpp:172] [insert] TimerQueue::insert() m_timers.size() : 1 m_activeTimers.size() : 1
  6. 2018-11-11 15:49:22.494058 [TRACE] [TimerQueue.cpp:55] [resetTimerfd] resetTimerfd()
  7. 2018-11-11 15:49:22.494066 [TRACE] [TimerQueue.cpp:172] [insert] TimerQueue::insert() m_timers.size() : 2 m_activeTimers.size() : 2
  8. 2018-11-11 15:49:22.494070 [TRACE] [TimerQueue.cpp:172] [insert] TimerQueue::insert() m_timers.size() : 3 m_activeTimers.size() : 3
  9. 2018-11-11 15:49:22.494073 [TRACE] [EventLoop.cpp:59] [loop] EventLoop 0x7FFFBD3C39B0 start loopig
  10. 2018-11-11 15:49:22.494075 [TRACE] [Poller.cpp:20] [poll] Poller::poll()
  11. 2018-11-11 15:49:23.495462 [TRACE] [Poller.cpp:28] [poll] nothing happended
  12. 2018-11-11 15:49:23.495488 [TRACE] [Poller.cpp:20] [poll] Poller::poll()
  13. 2018-11-11 15:49:24.496618 [TRACE] [Poller.cpp:28] [poll] nothing happended
  14. 2018-11-11 15:49:24.496640 [TRACE] [Poller.cpp:20] [poll] Poller::poll()
  15. 2018-11-11 15:49:25.494222 [TRACE] [Poller.cpp:24] [poll] 1 events happended
  16. 2018-11-11 15:49:25.494253 [TRACE] [TimerQueue.cpp:45] [readTimerfd] TimerQueue::handleRead() 1 at 1541922565.494251
  17. 2018-11-11 15:49:25.494316 [TRACE] [TimerQueue.cpp:188] [handleRead] Expired Timer size 2
  18. 2018-11-11 15:49:25.494320 [DEBUG] [main.cpp:50] [test] [test] : test timerQue
  19. 2018-11-11 15:49:25.494322 [DEBUG] [main.cpp:50] [test] [test] : test timerQue
  20. 2018-11-11 15:49:25.494325 [TRACE] [TimerQueue.cpp:55] [resetTimerfd] resetTimerfd()
  21. 2018-11-11 15:49:25.494332 [TRACE] [Poller.cpp:20] [poll] Poller::poll()
  22. 2018-11-11 15:49:26.496293 [TRACE] [Poller.cpp:28] [poll] nothing happended
  23. 2018-11-11 15:49:26.496318 [TRACE] [Poller.cpp:20] [poll] Poller::poll()
  24. 2018-11-11 15:49:27.494291 [TRACE] [Poller.cpp:24] [poll] 1 events happended
  25. 2018-11-11 15:49:27.494319 [TRACE] [TimerQueue.cpp:45] [readTimerfd] TimerQueue::handleRead() 1 at 1541922567.494317
  26. 2018-11-11 15:49:27.494328 [TRACE] [TimerQueue.cpp:188] [handleRead] Expired Timer size 1
  27. 2018-11-11 15:49:27.494331 [DEBUG] [main.cpp:50] [test] [test] : test timerQue
  28. 2018-11-11 15:49:27.494334 [TRACE] [Poller.cpp:20] [poll] Poller::poll()
  29. 2018-11-11 15:49:28.495665 [TRACE] [Poller.cpp:28] [poll] nothing happended
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号