1.定时器
- muduo的定时器由三个类实现,TimerId(外部类)、Timer、TimerQueue,用户只能看到第一个类,其它两个都是内部实现细节
- TimerQueue的接口很简单,只有两个函数addTimer和cancel
- EventLoop
runAt 在某个时刻运行定时器
runAfter 过一段时间运行定时器
runEvery 每隔一段时间运行定时器
上面三个函数会调用到TimerQueue.addTimer()
cancel 取消定时器
会调用到TimerQueue.cancel()
- TimerQueue数据结构的选择,能快速根据当前时间找到已到期的定时器(到期的定时器能够按照时间先后进行排序),也要高效的添加和删除Timer,因而可以用二叉搜索树,用map或者set
不使用map的原因是:
map<Timestamp, Timer*>,因为TimerQueue管理了很多定时器,有可能2个定时器的时间戳Timestamp是一样的,
但是实际的定时器操作Timer*是不一样的。
map不支持key是一样的,所以不适使用map
可以使用multimap,但是multimap不常用。后期可以尝试使用multimap
使用set的原因是:
typedef std::pair<Timestamp, Timer*> Entry;
typedef std::set<Entry> TimerList;//set只包含一个key,key的类型是pair对
<Timestamp, Timer*> 是整个key,即使Timestamp相等,但是定时器的地址Timer*也是不等的,所以key也是不等的。
- Channel的时序图
- EventLoop时序图
(1)Poller返回了activeChannels,首先回调handleEvent(),handleEvent()会根据Channels是POLLIN可读还是可写事件?来调用TimerQueue.handleRead();
(2)TimerQueue.handleRead()会getExpired()获取所有的超时的定时器,回调onTimer();
- eg:
28\jmuduo\muduo\net\TimerId.h
28\jmuduo\muduo\net\Timer.h
28\jmuduo\muduo\net\Timer.cc
28\jmuduo\muduo\base\Timestamp.h
28\jmuduo\muduo\net\TimerQueue.h
28\jmuduo\muduo\net\TimerQueue.cc
28\jmuduo\muduo\net\CMakeLists.txt
2.lower_bound&upper_bound
- eg1:
#include <set>
#include <iostream>
using namespace std;
int main(void)
{
int a[] = { 1, 2, 3, 4, 5 };
set<int> s(a, a+5);//key是int,set和map都会自动排序的
cout<<*s.lower_bound(2)<<endl;//会返回第一个值>=2的迭代器的位置,取*,//应该返回=2
cout<<*s.upper_bound(2)<<endl; ;//二分查找会返回第一个值>2的迭代器的位置,取*,应该返回=3
return 0;
}
- 测试:
3.RVO
-
返回值优化(Return Value Optimization,简称RVO)是一种编译器优化机制
-
eg:
struct Foo
{
Foo() { cout << "Foo ctor" << endl; }
Foo(const Foo&) { cout << "Foo copy ctor" << endl; }
void operator=(const Foo&) { cout << "Foo operator=" << endl; }
~Foo() { cout << "Foo dtor" << endl; }
};
Foo make_foo()
{
//return Foo();
Foo f;//这里调用构造函数
return f;//若没有RVO优化,这里会调用拷贝构造函数
//若有RVO优化,则会将对象f直接返回回去,不需要再拷贝构造,相当于对象f提升了,提升成不是一个局部对象,return时它不会释放的
}
int main(void)
{
make_foo();
return 0;
}
- 测试
使用vs2008 debug编译运行
使用vs2008 release编译运行
- eg测试:28\jmuduo\tests\Reactor_test04.cc
28\jmuduo\tests\CMakeLists.txt - 测试:
./build clean可以清空以前的编译文件
直到打印20次时,g_loop->quit(),则这里的loop.loop();也就退出来了