通过boost::circular_buffer + boost::unordered_set来模拟轮盘。
typedef boost::unordered_set<EntryPtr> Bucket;
typedef boost::circular_buffer<Bucket> WeakConnectionList;
WeakConnectionList connectionBuckets_;
特性:
1.支持随机访问
2.固定容量
3.插入元素超过容量时会对头部或者尾部元素弹出
circular_buffer会自动弹出元素的特性:
1.buffer的元素保存Bucket,这个Bucket是一个集合,保存在1秒内所有连接的shared_ptr
2.对buffer进行特定大小的初始化,并用空填满
3.当有一个连接的时候,将会把这个连接插入到Bucket里面
4.每一秒都会往buffer里面插入空的Bucket
5.这样基于circular_buffer的特性,现有的连接就会自动往前滚动
2.智能指针的使用
这里作者封装了一层结构Entry来管理TcpConnection,当circular_buffer将尾部 popback的时候,会依次调用其析构函数,并在析构函数主动断开连接。
当时有两个疑问:
1.一个是在看源码时,每个TcpConnection有一个上下文Context变量保存Entry的WeakPtr。
所谓上下文,就是变量,因为回调机制,每个连接都需要有其关联的Entry,这里直接用WeakPtr来作为上下文变量,不影响其引用计数。有了上下文,服务器每当收到客户端的消息时(onMessage),可以拿到与该连接关联的Entry的弱引用,再把它提升到强引用,插入到circular_buffer,这样就相当于把更新了该连接在时间轮盘里面的位置了,相应的use_count会加1。
2.一个是运行example时(build/release/bin/idleconnection_echo)每当有新的连接(onConnection),或者有新的消息(onMessage)时,智能指针对象的use_count都会先加2,然后再恢复正常的加1。
EntryPtr entry(new Entry(conn));
/*conn插入时间轮盘*/
connectionBuckets_.back().insert(entry);
dumpConnectionBuckets();
通过此处增加计数
在onConnection回调中,这里先创建了一个栈上shared_ptr,之后插入到unordered_set中,这里就会有引用计数就增加了两次,之后栈上变量销毁,引用计数回归正常。
#include <iostream>
#include <memory>
#include <unordered_set>
using namespace std;
typedef shared_ptr<int> IntPtr;
typedef unordered_set<IntPtr> IntPtrSet;
int main()
{
IntPtrSet myset;
{
IntPtr ptr(new int(42));
cout<<ptr.use_count()<<endl;
myset.insert(ptr);
auto it = myset.begin();
cout<<it->use_count()<<endl;
}
auto it = myset.begin();
cout<<it->use_count()<<endl;
return 0;
}
//打印结果
//1
//2
//1