[经验总结]调用WinSock的closesocket函数出现死锁的解决办法

       这两天调试一个网络应用程序,出现一个很诡异的问题:程序在关闭连接时失去响应。用Process Explorer工具查看该程序的各个线程,发现一个工作线程的调用栈类似这样: stopProc ==> closesocket ==> EnterCriticalSection ==> RTEnterCriticalSection .... .... 

 

       看到CriticalSectoin的相关调用,我想到closesocket函数可能遇到了死锁。一个看似简单的closesocket还需要加锁吗? 带着这个疑问,我翻出了ReactOS和wine的源代码。在这两份代码中,socket句柄都存储在内核维护的一个双向链表中,closesocket执行的操作就是将socket句柄从链表中删除,这样当然需要采用同步机制,以保证同一个时刻只有一个线程能操作链表。closesocket函数采用了关键段来同步socket链表操作,所以在Process Explorer中能看到EnterCriticalSection调用。

 

       分析到这里,还是没能解决问题,到底是什么原因导致死锁。我又开始查MSDN,查看了closesocket相关资料,知道了grace shutdown这个“新名词”,还试了几个偏方,如设置SO_REUSEADDR属性,设置shutdown的linger参数,无奈还是没能解决问题。不过此般学习倒是让我开始注意了关闭连接时的收发操作。这时,我再次回到自己的代码,走查了相关代码,发现当closehandle时,另外一个工作线程会有收发(recv、send)调用,这两个调用很可能是导致closesocket死锁的“元凶”。为了验证这个观点,我用英文关键词Google了一般(之前没找到有用的中文信息),发现了这个帖子"close socket deadlocks blocked threads",虽然帖子中提到的是BSD系统的问题,但其现象我遇到的一样。所以,到现在,我几乎可以肯定,死锁原因就是那个工作线程中的收发调用。接下来的解决办法就比较简单了:在closesocket调用之前,关闭所有可能调用 recv、send的线程。直接关闭线程的做法比较粗暴,但在我的代码,这样的修改是可行的。

 

       总结一下,如果在关闭socket时,有另外的线程在利用这个socket进行收发,那么closesocket可能会死锁。解决的办法就是在closesocket调用之前,关闭所有的recv、send操作。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值