修改一行代码的顺序引发恶心bug
起因
原来的代码
m_recvBuffer->Clear();
m_multiplexor->Register(this, Herm::READ_MASK);
Session初始化的时候,先把接收buffer清空,再注册读事件。
几周前,加了一个小功能, 抽了一个小函数,最后代码顺序变化了一下
m_multiplexor->Register(this, Herm::READ_MASK);
m_recvBuffer->Clear();
这个东西是前几年整理的,这几年基本没怎么动了,细节流程没有完全存在脑子里,一开始根本没有想到是几周改的出现问题。
首先怀疑是应用层的对象是不是越界把地下的通信Session给写坏了。比较棘手的是,用测试程序也不容易重现这个bug,正常调试一点问题都没有。
花了好几个小时,各种可能一一排除了,最后根据一个现象,刚开始的时候m_recvBuffer有数据,但后面的时候,内部数据读写位置(这个buffer是环形队列)直接全变成0了。
上层直接把这个buffer给清掉了?把应用逻辑全去掉,用测试工具测,还是会出现。说明问题还是在底层代码本身。 后来怀疑到m_recvBuffer->Clear()头上,这个东西是把
buffer内部的读写位置全清0的。
bug分析
主线程
连接过来的时候,主线程先创建一个 socket handle,调用上面两行代码,清空buffer,同时注册读事件到epoll。
通信线程
当主线程注册读事件的时候,socket buffer有数据会马上得到通知,立刻把数据直接收到m_recvBuffer。
main thread Register Read
net thread Receive(m_recvBuffer, ....);
main thread m_recvBuffer->Clear(); // 这个时候刚收到的数据就没有了。
m_recvBuffer->Clear()放在m_multiplexor->Register(this, Herm::READ_MASK);前面,这个Bug基本可以避免(其实没有Memory Barrier情况下,处理器并不能保证Clear()一定在Register()前面, 但从实际情况看,这个概率事件可以不考虑了)。
blog.csdn.net/herm_lib