某些用户,机器重启后,到第三方服务器的连接起不来,而到我们自己服务器的连接就没事。


如果连接由于网络或其他原因fail掉,过一定时间后应该会重新尝试建立连接的。

测试组做初步调查,他们能在本地环境复现,只是不是稳定复现,时而有时而没有。(嗯,race condition的问题就常常比较飘忽不定,并且往往在系统繁忙负载高的时候爆发)。我开始参与。

分析了一下现有的log,不能得出任何结论。所以在代码中另外增加了一些debug log,然后测试组再跑... 最后终于看到问题根本。

我们有两种类型的链路,分开管理,但基本的socket特性是共享代码的。


这个到第三方服务器的接口,是没有应用层的保活(或者说心跳)协议的。需要依靠TCP层的状态和事件来管理连接。并且这个第三方也禁止持久连接,只能需要发请求的时候按需建立连接。空闲时(没有请求需要发送),需要把连接关闭。所以连接内部有一种状态是"Idle Closed", 表示连接因为闲置而关闭但相信是健康的。


最初代码里的设计是有点倾向异步的。跟我们自己的服务器的链路,连接是这样建立的:一个线程对一个非阻塞socket调用connect() ,(将状态标识为Connecting),然后另外一个线程对所有在Connecting 状态的socket做select()来探测可写事件。如果捕获可写事件,则连接状态变为Connected。


也许部分是由于第三方链路的非持久特性,或是写代码的简易性(调用一个函数返回之后连接要么建立成功要么失败,明显代码流简单很多),跟第三方服务器的连接是同步地建立的。一个线程调用名字像****ConnectSync()这样的一个函数来同步地建立连接。然而,里面用到的系统调用却不是同步的那一个connect:对一个非阻塞socket调用connect(),(将状态标识为Connecting),然后阻塞在一个select()调用。select() 得到可写事件或者超时****ConnectSync()就返回,这样****ConnectSync() 就看起来像同步的。
 
如果一个socket在****ConnectSync()被设为Connecting状态,另外一个线程会对这个socket调用select() 来探测可写事件。


两个线程对同一个socket调用select(),只有其中一个线程可以获得代表连接被建立起来的可写事件 (至少在Windows平台上是这样)。
所以,一个线程把连接标识为connected 然后idle closed掉它,另外一个线程认为连接失败(因为没得到可写事件)所以把连接标识为not Available。

如果一个链路即是 idle closed的又是not Available的,那将不再对它做链路测试(因为idle closed表明链路是健康的),也不会再有请求来的时候选中它来建立连接(not Available所以不会被选中)。(嗯,链路的多个标志位也让人看起来有点混乱) 所以到第三方服务器的链路才会永久性失败,因为再也不会尝试它了。


修复很明显...

-------------------------------------------------------------------------------------------------

阅读更多博文可订阅RSS,了解更多最新动态可关注微博 @千里孤行Nerd

遭遇多线程bug (1)的更多相关文章

  1. 实现TOLock过程中的一处多线程bug

    背景 最近在啃<多处理器编程的艺术>,书中的7.6节介绍了时限锁--实现了tryLock方法的队列锁. 书中重点讲解了tryLock的实现,也就是如何实现在等待超时后退出队列,放弃锁请求, ...

  2. AppStore遭遇大BUG

    用AppLoader上传,提示这个 The u option must have a non-empty value.The password must have a non-empty value. ...

  3. jdk1.6空轮询Bug的原因及解决方法

    简述 本文主要介绍一下jdk1.6版本中的NIO Selector空轮询BUG,描述一下BUG的现象及原因,以及Netty中如何巧妙的规避了这个bug. 为什么要写这篇文章,说来惭愧,很久以前面试官问 ...

  4. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  5. 第二单元总结:基于synchronize锁的简单多线程设计

    单元统一的多线程设计策略 类的设计 电梯 每部电梯为一个线程. 电梯从调度器接收原子指令,知晓自己的状态(内部的人/服务的人.运行方向.所在楼层) 原子指令包括且仅包括: 向上走一层 / 向下走一层 ...

  6. j2ee高并发时使用全局变量需要注意的问题

    原文:https://blog.csdn.net/jston_learn/article/details/21617311 开发中,全局变量的使用很频繁,但对于多线程的访问,使用全局变量需要注意的地方 ...

  7. Qt on Android 核心编程

    Qt on Android 核心编程(最好看的Qt编程书!CSDN博主foruok倾力奉献!) 安晓辉 著   ISBN 978-7-121-24457-5 2015年1月出版 定价:65.00元 4 ...

  8. IOS学习之路--OC的基础知识

    1.项目经验 2.基础问题 3.指南认识 4.解决思路 ios开发三大块: 1.Oc基础 2.CocoaTouch框架 3.Xcode使用 -------------------- CocoaTouc ...

  9. iOS求职之OC面试题

    1.Objective-C的类可以多重继承么?可以采用多个协议么? 答:不可以多重继承,可以采用多个协议. 2.#import和#include的区别是什么?#import<> 跟 #im ...

随机推荐

  1. 十二、C# 委托与Lambda表达式(匿名方法的另一种写法)

    委托与Lambda表达式   1.委托概述 2.匿名方法 3.语句Lambda 4.表达式Lambda 5.表达式树   一.委托概述 相当于C++当中的方法指针,在C#中使用delegate 委托来 ...

  2. 【转】无废话WCF系列教程

    转自:http://www.cnblogs.com/iamlilinfeng/category/415833.html     看后感:这系列的作者李林峰写得真的不错,通过它的例子,让我对WCF有了一 ...

  3. TaskbarCreated 消息

    托盘中的图片就通过注册这个消息来实现,系统和进程通过进程间通信发送这个消息,进程接收他

  4. javascript常用代码大全

    http://caibaojian.com/288.html    原文链接 jquery选中radio //如果之前有选中的,则把选中radio取消掉 $("#tj_cat .pro_ca ...

  5. QTP插入Output Value和插入CheckPoint,注意点

    1. 必须打开程序才能进行Output value和CheckPoint的插入. 2. 也有可能是对象获取不到,从新加载对象库. 提示如下图:

  6. Trigger model Trigger expr_id in WorkFolow

    For example, suppose you want to set a Sale Order into the state "Done" once it has been s ...

  7. iscc2016-basic-find-to-me

    额 第一题就暴力搜索了 已知仿射加密变换为c=(11m+8)mod26,试对密文sjoyuxzr解密 #include <stdio.h> int main(void) { int m,c ...

  8. 转:PHP的线程安全ZTS与非线程(NTS)安全版本的区别

    原文来自于:http://blog.sina.com.cn/s/blog_94c21e8f0101s2ic.html Windows版的PHP从版本5.2.1开始有Thread Safe(线程安全)和 ...

  9. C++例题1:输出可打印字符

    #include<iostream>#include<stdlib.h>#include<cctype>int main(){ int i;char a=0; fo ...

  10. HDU1106

    为了给学弟学妹讲课,我又水了一题-- 1: import java.util.*; 2: import java.io.*; 3: 4: public class HDU1106 5: { 6: pu ...