解决了一个困惑很久的bug
来源:互联网 发布:sqlserver分布式查询 编辑:程序博客网 时间:2024/06/11 00:32
让这个bug困扰了很久,前一段太忙只找了个临时解决方案而没有追究原因,今天终于把它搞清楚了。由于测试时只在多cpu系统上出现,我甚至一度怀疑它是cpu的bug 。
两个c/s结构的网络通讯程序,服务器端使用完成端口模型,客户端使用阻塞模型,双方以一种客户端发送命令,服务器端处理,然后返回应答的方式通讯。问题出在服务器端。以下是服务器端代码的大致处理逻辑:
long volatile g_busy = 0;void iocp_thread(){while( GetQueuedCompletionStatus() ){if( InterlockedCompareExchange( &g_busy, 1, 0 ) != 0 )WSASend( "服务器忙" );// 处理命令ProcessCommand();WSASend( "应答信息" );InterlockedExchange( &g_busy, 0 );}}
其中ProcessCommand需要互斥运行(这是简化的逻辑,实际上有很多不同的命令,有些需要互斥,有些可以并行,否则就没必要用完成端口了),并且需要一定的时间才能处理完毕。为了避免多个客户端同时执行命令,导致所有的iocp线程都等在那,我把g_busy当成了一个锁,第一个线程可以成功进入,其它的都直接向客户端返回“服务器忙”。
程序一直都运行的很好,直到有一天把服务器程序装到了一台有双核cpu的机器上。我发现,如果让客户端连续发送命令,即收到上一条命令的应答后立即发送下一条命令,就会随机的返回“服务器忙”,而这时只有一个客户端连接上去,按照我设想的逻辑是不可能出这种情况的。检查了半天代码,没觉得有什么问题,调试吧,又遇到了另一个难题,海森堡的测不准原理起作用了,做的工作太多问题就消失了,做的太少又得不到什么有价值的信息。搞得我很是头疼。
今天再次看这个问题,突然想到:它肯定和线程切换相关,所以我应该记录下每次处理命令的线程的ID,这样出错时就可以看看上次成功执行命令的那个线程在干什么了。方法正确了,问题也就迎刃而解了,我发现,出问题时,上一个线程的WSASend居然还没有返回,也就是说,客户端已经收到应答并发送了下一条命令,服务器端也收到了命令并准备处理,但上一条命令的应答却还没有完全发送完成,难怪出错了!
总结经验教训,感觉自己一开始被两点给误导了,一是实际程序中的WSARecv/WSASend藏的比较深,没这么明显,所以没注意到。二是当时粗略检查代码觉得没问题,就把主要精力放在ProcessCommand上了,由于我把它里面一段访问sql server的代码注释掉以后,问题就不出了,所以还看了半天atl oledb的源码,最后精疲力尽,其它事情又比较多就放弃了。
- 解决了一个困惑很久的bug
- 困惑了很久的函数D3DXCreateTextureFromFileInMemoryEx
- 困惑了我很久的一道题
- 找了很久的bug
- 今天非常高兴,解决了一个关于java类转json时有关联对象而且困扰我很久的BUG
- 当一个bug困扰你很久都解决不了的时候,它很可能就是一个低级错误
- 一个感动了我很久的故事
- 很久了,有一个软件的构想。
- 一个搞了很久的SQL
- 一个放了很久的网站程序
- 有一个关于collectiview的问题,弄了很久自己也没有解决
- 有一个关于collectiview的问题,弄了很久自己也没有解决
- DataTable.Select()方法的一个困惑,或者是一个bug?
- 写了一个小的网站困惑
- 解决了jquery.bgiframe.min.js的一个bug
- 解决了一个Web网页显示不全的BUG
- 解决了一个butterknife,报空指针的bug
- 今天解决了一个bug,是一个页面渲染丢失页面的bug
- 经典SQL Server用户自定义函数:首字拼音查询
- Asp.net发邮件
- 删除串中相同的元素:一个做法
- asp.net投票进度条显示
- ASP.net 2.0中水晶报表迁移部署问题
- 解决了一个困惑很久的bug
- 3D Demo
- Asp.net验证码
- 固定水晶报表每页显示的行数两种方法
- ASP.NET中正则表达非JS
- javascript的函数
- tcpdump的使用方法
- datalist分页
- 如何彻底卸载oracle