Muduo网络编程之使用Timing wheel 踢掉空闲连接

这部分原理可以直接参考http://blog.csdn.net/solstice/article/details/6395098。

本文记录自己的理解和部分代码注释。

1.模拟轮盘

通过boost::circular_buffer来模拟轮盘。简单学习了一下关于这个数据结构的内容。
它有如下特性:

1.支持随机访问
2.固定容量
3.插入元素超过容量时会对头部或者尾部元素弹出

下面看一个简单示例:

#include 
#include 
#include 


using namespace std;
using namespace boost;


void print(const circular_buffer<int>& nums) {
    for (int i = 0; i < nums.size(); ++i) {
        cout << nums[i] << " ";
    }
    cout << endl;
}


int main(int argc, char* argv[]) {
    circular_buffer<int> nums(5);     //声明一个总容量为5的circular_buffer
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);
    nums.push_back(4);
    nums.push_back(5);
    print(nums);
    nums.push_back(6);
    print(nums);
    nums.push_front(7);
    print(nums);
    nums[3] = 9;
    print(nums);
    nums.pop_back();
    print(nums);
    nums.pop_front();
    print(nums);
    return 0;
}

运行结果如下:

Muduo网络编程之使用Timing wheel 踢掉空闲连接_第1张图片

作者基于circular_buffer会自动弹出元素的特性,做了如下模拟:

1.buffer的元素保存Bucket,这个Bucket是一个集合,保存在1秒内所有连接的shared_ptr
2.对buffer进行特定大小的初始化,并用hole填满
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。例如图:

Muduo网络编程之使用Timing wheel 踢掉空闲连接_第2张图片

括号里面表示 use_count。看代码:

EntryPtr entry(new Entry(conn));
/*conn插入时间轮盘*/
connectionBuckets_.back().insert(entry);
dumpConnectionBuckets();

原因找到了,在onConnection回调中,这里先创建了一个栈上shared_ptr,之后插入到unordered_set中,这里就会有引用计数就增加了两次,之后栈上变量销毁,引用计数回归正常。

写了一个类似的测试程序:

#include 
#include 
#include 
using namespace std;
typedef shared_ptr<int> IntPtr;
typedef unordered_set IntPtrSet;
int main()
{
    IntPtrSet myset;
    {
        IntPtr ptr(new int(42));
        cout<auto it = myset.begin();
        cout<use_count()<auto it = myset.begin();
    cout<use_count()<return 0;
}
//打印结果
//1
//2
//1

3.参考

1.《Linux多线程网络编程使用muduoC++网络库》
2.http://m.blog.csdn.net/article/details?id=7167915

你可能感兴趣的:(muduo和多线程学习)