UDT源码剖析(四):UDT的GC线程相关过程代码注释

着UDT::Startup()的启动,GC线程也随之运行了。
GC主要关注的就是UDTSocket的释放,下面我们来看看这个GC线程是怎么实现的。

查看源代码
打印帮助
1 #ifndef WIN32
2    void* CUDTUnited::garbageCollect(void* p)
3 #else
4    DWORD WINAPI CUDTUnited::garbageCollect(LPVOID p)
5 #endif
6 {
7    // 获得当前GC对应的Socket单位
8    CUDTUnited* self = (CUDTUnited*)p;
9  
10    // 应用锁保护,这里的锁是CUDTUnited::m_GCStopLock
11    CGuard gcguard(self->m_GCStopLock);
12  
13    // 如果Socket单位没有标记为关闭中,那么GC持续生效
14    while (!self->m_bClosing)
15    {
16       self->checkBrokenSockets();
17  
18       #ifdef WIN32
19          self->checkTLSValue();
20       #endif
21  
22       // 这里处理超时解锁,windows下的WaitForSingleObject函数直接输入超时时间间隔
23       // 而非windows的需要提供绝对时间,所以需要先根据当前时间得到超时时间,然后作为参数传入pthread_cond_timedwait
24       // 实际上就是当计时器用,确保两次检查的时间间隔最多为1秒钟
25       #ifndef WIN32
26          timeval now;
27          timespec timeout;
28          gettimeofday(&now, 0);
29          timeout.tv_sec = now.tv_sec + 1;
30          timeout.tv_nsec = now.tv_usec * 1000;
31  
32          pthread_cond_timedwait(&self->m_GCStopCond, &self->m_GCStopLock, &timeout);
33       #else
34          WaitForSingleObject(self->m_GCStopCond, 1000);
35       #endif
36    }
37  
38    // 到这里说明Socket单位处于正在关闭的状态
39  
40    // remove all sockets and multiplexers
41    // 移除所有的Sockets和多路复用器
42  
43    // 启动锁保护,这里不直接用CGuard是因为要多次用到这个锁,并且在下面的checkBrokenSockets中也要使用该锁,所以手动处理
44    CGuard::enterCS(self->m_ControlLock);
45    for (map<UDTSOCKET, CUDTSocket*>::iterator i = self->m_Sockets.begin(); i != self->m_Sockets.end(); ++ i)
46    {
47       // 标记作废,调用关闭,并标记为CLOSED,更新时间戳,将Socket对象加入已关闭列表
48       i->second->m_pUDT->m_bBroken = true;
49       i->second->m_pUDT->close();
50       i->second->m_Status = CLOSED;
51       i->second->m_TimeStamp = CTimer::getTime();
52       self->m_ClosedSockets[i->first] = i->second;
53  
54       // remove from listener's queue
55       // 从监听列表中移除
56       map<UDTSOCKET, CUDTSocket*>::iterator ls = self->m_Sockets.find(i->second->m_ListenSocket);
57       if (ls == self->m_Sockets.end())
58       {
59           // 如果在Socket列表和已关闭列表中都未找到监听Socket,则不作处理
60          ls = self->m_ClosedSockets.find(i->second->m_ListenSocket);
61          if (ls == self->m_ClosedSockets.end())
62             continue;
63       }
64  
65       // 运行到这里说明找到了监听Socket
66       // 从监听Socket的待Accept及已Accept列表中移除当前Socket
67       CGuard::enterCS(ls->second->m_AcceptLock);
68       ls->second->m_pQueuedSockets->erase(i->second->m_SocketID);
69       ls->second->m_pAcceptSockets->erase(i->second->m_SocketID);
70       CGuard::leaveCS(ls->second->m_AcceptLock);
71    }
72    // 已移除所有Socket项目,清空列表
73    self->m_Sockets.clear();
74  
75    // 将已关闭列表中的所有项时间戳标记为0
76    for (map<UDTSOCKET, CUDTSocket*>::iterator j = self->m_ClosedSockets.begin(); j != self->m_ClosedSockets.end(); ++ j)
77    {
78       j->second->m_TimeStamp = 0;
79    }
80  
81    // 手动解锁
82    CGuard::leaveCS(self->m_ControlLock);
83  
84    while (true)
85    {
86       // 检查作废Socket,直到已关闭Socket列表为空
87       self->checkBrokenSockets();
88  
89       CGuard::enterCS(self->m_ControlLock);
90       bool empty = self->m_ClosedSockets.empty();
91       CGuard::leaveCS(self->m_ControlLock);
92  
93       if (empty)
94          break;
95  
96       CTimer::sleep();
97    }
98  
99    #ifndef WIN32
100       return NULL;
101    #else
102       return 0;
103    #endif
104 }
1 void CUDTUnited::checkBrokenSockets()
2 {
3    CGuard cg(m_ControlLock);
4  
5    // set of sockets To Be Closed and To Be Removed
6    // tbc要关闭的Socket列表
7    // tbr要移除的Socket列表
8    vector<UDTSOCKET> tbc;
9    vector<UDTSOCKET> tbr;
10  
11    // 循环单元中所有Socket
12    for (map<UDTSOCKET, CUDTSocket*>::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++ i)
13    {
14       // check broken connection
15       // 检查状态是否为已作废
16       if (i->second->m_pUDT->m_bBroken)
17       {
18          if (i->second->m_Status == LISTENING)
19          {
20             // for a listening socket, it should wait an extra 3 seconds in case a client is connecting
21             // 如果该Socket是一个监听Socket,那么需要在作废后3秒钟再处理该Socket,因为可能有客户端正在连接
22             if (CTimer::getTime() - i->second->m_TimeStamp < 3000000)
23                continue;
24          }
25          else if ((i->second->m_pUDT->m_pRcvBuffer->getRcvDataSize() > 0) && (i->second->m_pUDT->m_iBrokenCounter -- > 0))
26          {
27             // if there is still data in the receiver buffer, wait longer
28             // 如果接收缓存中还有数据,并且检查计数大于0,则暂不处理
29             // 检查计数m_iBrokenCounter,在通常情况下为30,调用shutdown时为60,可以理解为30秒、60秒
30             continue;
31          }
32  
33          //close broken connections and start removal timer
34          // 关闭作废的连接,并移除计时器
35          // 标记状态为CLOSED,更新时间戳为当前,将Socket加入要关闭的Socket列表
36          i->second->m_Status = CLOSED;
37          i->second->m_TimeStamp = CTimer::getTime();
38          tbc.push_back(i->first);
39          m_ClosedSockets[i->first] = i->second;
40  
41          // remove from listener's queue
42          // 从监听列表中移除
43          map<UDTSOCKET, CUDTSocket*>::iterator ls = m_Sockets.find(i->second->m_ListenSocket);
44          if (ls == m_Sockets.end())
45          {
46              // 如果在Socket列表和已关闭列表中都未找到监听Socket,则不作处理
47             ls = m_ClosedSockets.find(i->second->m_ListenSocket);
48             if (ls == m_ClosedSockets.end())
49                continue;
50          }
51  
52          // 运行到这里说明找到了监听Socket
53          // 从监听Socket的待Accept及已Accept列表中移除当前Socket
54          CGuard::enterCS(ls->second->m_AcceptLock);
55          ls->second->m_pQueuedSockets->erase(i->second->m_SocketID);
56          ls->second->m_pAcceptSockets->erase(i->second->m_SocketID);
57          CGuard::leaveCS(ls->second->m_AcceptLock);
58       }
59    }
60  
61    // 遍历已关闭Socket列表中的项
62    for (map<UDTSOCKET, CUDTSocket*>::iterator j = m_ClosedSockets.begin(); j != m_ClosedSockets.end(); ++ j)
63    {
64       // 有犹豫时间
65       if (j->second->m_pUDT->m_ullLingerExpiration > 0)
66       {
67          // asynchronous close:
68          // 异步关闭
69          // 关闭条件为:发送列表已经为空,或者发送列表的当前缓存大小为0,或者超出犹豫时间
70          if ((NULL == j->second->m_pUDT->m_pSndBuffer) || (0 == j->second->m_pUDT->m_pSndBuffer->getCurrBufSize()) || (j->second->m_pUDT->m_ullLingerExpiration <= CTimer::getTime()))
71          {
72             j->second->m_pUDT->m_ullLingerExpiration = 0;
73             j->second->m_pUDT->m_bClosing = true;
74             j->second->m_TimeStamp = CTimer::getTime();
75          }
76       }
77  
78       // timeout 1 second to destroy a socket AND it has been removed from RcvUList
79       // Socket被标记时间戳后1秒钟,并且已经从接收列表节点中移除,那么把它放入可移除列表
80       if ((CTimer::getTime() - j->second->m_TimeStamp > 1000000) && ((NULL == j->second->m_pUDT->m_pRNode) || !j->second->m_pUDT->m_pRNode->m_bOnList))
81       {
82          tbr.push_back(j->first);
83       }
84    }
85  
86    // move closed sockets to the ClosedSockets structure
87    // 将tbc可关闭Socket列表中的对象从当前Socket列表中移除,这里作者的注释有问题
88    // 实际上在上面m_ClosedSockets[i->first] = i->second;已经把这些Socket添加到ClosedSockets中了
89    for (vector<UDTSOCKET>::iterator k = tbc.begin(); k != tbc.end(); ++ k)
90       m_Sockets.erase(*k);
91  
92    // remove those timeout sockets
93    // 对tbr可移除Socket列表中的项执行removeSocket
94    for (vector<UDTSOCKET>::iterator l = tbr.begin(); l != tbr.end(); ++ l)
95       removeSocket(*l);
96 }
1 void CUDTUnited::removeSocket(const UDTSOCKET u)
2 {
3    // 可移除的Socket必须在m_ClosedSockets列表中存在
4    map<UDTSOCKET, CUDTSocket*>::iterator i = m_ClosedSockets.find(u);
5  
6    // invalid socket ID
7    // 如果不存在则不予移除
8    if (i == m_ClosedSockets.end())
9       return;
10  
11    // decrease multiplexer reference count, and remove it if necessary
12    // 获取复用器ID
13    const int mid = i->second->m_iMuxID;
14  
15    // 如果待Accept队列不为空
16    if (NULL != i->second->m_pQueuedSockets)
17    {
18       CGuard::enterCS(i->second->m_AcceptLock);
19  
20       // if it is a listener, close all un-accepted sockets in its queue and remove them later
21       // 如果当前Socket是一个监听Socket,就要关闭所有尚未Accept的连接并在稍后将它们移除
22       for (set<UDTSOCKET>::iterator q = i->second->m_pQueuedSockets->begin(); q != i->second->m_pQueuedSockets->end(); ++ q)
23       {
24          m_Sockets[*q]->m_pUDT->m_bBroken = true;
25          m_Sockets[*q]->m_pUDT->close();
26          m_Sockets[*q]->m_TimeStamp = CTimer::getTime();
27          m_Sockets[*q]->m_Status = CLOSED;
28          m_ClosedSockets[*q] = m_Sockets[*q];
29          m_Sockets.erase(*q);
30       }
31  
32       CGuard::leaveCS(i->second->m_AcceptLock);
33    }
34  
35    // remove from peer rec
36    // 从m_PeerRec中移除该Socket信息
37    // m_PeerRec用来记录连接节点信息以防止重复的连接请求,必须在关闭时移除以保证下次连接不会被拒绝
38    map<int64_t, set<UDTSOCKET> >::iterator j = m_PeerRec.find((i->second->m_PeerID << 30) + i->second->m_iISN);
39    if (j != m_PeerRec.end())
40    {
41       j->second.erase(u);
42       if (j->second.empty())
43          m_PeerRec.erase(j);
44    }
45  
46    // delete this one
47    // 关闭、删除当前Socket对象,并从m_ClosedSockets列表中移除
48    i->second->m_pUDT->close();
49    delete i->second;
50    m_ClosedSockets.erase(i);
51  
52    // 从复用器列表中查找当前的复用器
53    map<int, CMultiplexer>::iterator m;
54    m = m_mMultiplexer.find(mid);
55    if (m == m_mMultiplexer.end())
56    {
57       //something is wrong!!!
58       // 如果没找到肯定有什么地方搞错了,但是这里没做处理
59       return;
60    }
61  
62    // 把当前复用器所对应的UDT计数减一
63    // 如果减至0,说明已经没有可复用的UDT对象,则从复用器列表中将当前复用器移除
64    m->second.m_iRefCount --;
65    if (0 == m->second.m_iRefCount)
66    {
67       m->second.m_pChannel->close();
68       delete m->second.m_pSndQueue;
69       delete m->second.m_pRcvQueue;
70       delete m->second.m_pTimer;
71       delete m->second.m_pChannel;
72       m_mMultiplexer.erase(m);
73    }
74 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/464027.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

那年高考

每年高考&#xff0c;都会让我想起很多事情。我第一次高考前几天&#xff0c;我舅舅和舅娘过来看我&#xff0c;他们拉我到教室后门&#xff0c;我舅说我妈叮嘱他一定来看我&#xff0c;然后跟我说不要给自己太大压力&#xff0c;啰嗦了几分钟&#xff0c;要走的时候硬塞给我10…

vimdiff的简单使用

Vimdiff的使用 1、首先vimdiff是一款高效的文件的比较和合并的工具&#xff0c;它具有以下一些特点&#xff1a;命令行方式的比较工具&#xff1b;简单明了的界面&#xff1b;对比较出来的多处差异之间快速定位&#xff1b;进行文件合并。再使用vimdiff命令之前&#xff0c;我们…

拆解一个比亚迪的车钥匙,这个黑黑的元器件是什么?

今天抽屉突然找到一个比亚迪的车钥匙&#xff0c;寻思着没事拆开看看用什么方案做的。正面照&#xff0c;哪款车型的&#xff0c;不知道了背面照&#xff0c;很简洁&#xff0c;只有一个BYD的Logo接下来就是撬开了&#xff0c;过程非常顺利&#xff0c;之前撬开一个宝马车的钥匙…

分布式事物(同样适用于dubbo事务等分布式事务)

转载于:https://www.cnblogs.com/tian1993/p/10081901.html

一些web开发中常用的、做成cs文件的js代码 - 搜刮来的

using System;using System.Web;using System.Web.UI;namespace COCOWO.COMP{ /// <summary> /// 一些常用的Js调用 /// 创建时间&#xff1a;2006-8-3 /// 创建者&#xff1a;马先光 /// </summary> public class Jscript { …

库里扛起了勇士对凯尔特人的第四场

最近临近毕业季&#xff0c;有朋友这样说「我一定是要支持勇士的&#xff0c;毕竟库里和詹姆斯陪了整个大学四年啊」。昨晚上加班到11点半&#xff0c;到家洗完澡已经是凌晨1点了&#xff0c;那时候是想得很清楚的&#xff0c;明天是不想被其他事情打扰我看球赛的。这场比赛&am…

Nginx应用案例分享:压力测试

2019独角兽企业重金招聘Python工程师标准>>> 在运维工作中&#xff0c;压力测试是一项非常重要的工作。比如在一个网站上线之前&#xff0c;能承受多大访问量、在大访问量情况下性能怎样&#xff0c;这些数据指标好坏将会直接影响用户体验。 但是&#xff0c;在压力…

shell 判断文件是否存在,没有则创建

没有该文件则创建&#xff0c;有则 ls -l 输出文件信息。 #!/bin/bash echo "enter the name:" read filename if test -e $filename ; then ls -l $filename else touch $filename fi 输出 enter the name: sss.sh -rwxr-xr-x 1 root root 147 Dec 3 09:02 sss.sh …

声音是什么?

转自博客园《【秒懂音视频开发】02_重识声音》&#xff0c;https://www.cnblogs.com/mjios/p/14466418.html#5035688#!comments声音的产生声音&#xff08;Sound&#xff09;&#xff0c;是由物体的振动产生的。一切正在发声的物体都在振动。我们说话的时候&#xff0c;是声带在…

c#中的常用ToString()方法总结。

很多类都重写了ToString方法&#xff0c; 导致很多类的tostring到底执行了什么&#xff0c;有哪些参数&#xff0c;都不清楚。。。。很郁闷&#xff01;对于int&#xff0c;double等的tostring&#xff1a;C 货币 2.5.ToString("C") &#xffe5;2.50…

UDT源码剖析(五):UDT::cleanup()过程代码注释

调用路线 UDT::cleanup()->CUDT::cleanup()->CUDTUnited::cleanup() 1 int CUDTUnited::cleanup() 2 { 3 // 锁保护 4 CGuard gcinit(m_InitLock); 5 6 // 如果还有实例运行&#xff0c;则到此为止了 7 if (--m_iInstanceCount > 0) 8 return 0; …

《星辰傀儡线》人物续:“灭世者”、“疯狂者”、“叛逆者”三兄妹

“灭世者”、“疯狂者”、“叛逆者”三兄妹&#xff1a;“灭世者”黑卡蒂&#xff1a;卡西欧家族的科技天才&#xff0c;沉默&#xff0c;不爱说话&#xff0c;一对亮闪闪的氪金眼&#xff0c;黑暗军团一战后&#xff0c;以“天空之镜”的设计者而闻名。柏拉图“理想国”的拥有…

[源码和文档分享]基于C语言的语法高亮设计与实现

一 需求分析 在所需高亮的关键字或字符串前后加上class标签&#xff0c;在css定义颜色。 二 程序设计 2.1 设计思路 把.html文件和.css文件中的内容存在两个字符数组中&#xff0c;在.cpp用文件操作写入。 2.2 文件组织架构 Syntax highlighting.exe所在目录为根目录 源代码命…

在.NET中用excel导出(概要)

首先要在项目->添加引用->COM中添加Microsoft Office Web Components &#xff0c;然后定义一个OWC.SpreadsheetClass 如&#xff1a;Dim xlsheet As New OWC.SpreadsheetClass 然后就可以向sheet中添加数据了&#xff0c;使用xlsheet.Cells(2, 2) "表格填充内容&q…

我愿为这二极管奉献我的一生

简 介&#xff1a; 利用二极管完成对信号的整流&#xff0c;求取绝对值等具有很多的应用。然而在小信号下&#xff0c;二极管的前向导通电压以及相应的杂散电容会对信号整流带来严重的影响。本文从“马场清太郎”所著的“运算放大器应用电路设计”中摘取了一些典型应用电路&…

61条Java面向对象设计的经验原则

1&#xff09;所有数据都应该隐藏在所在的类的内部。 &#xff08;2&#xff09;类的使用者必须依赖类的共有接口&#xff0c;但类不能依赖它的使用者。 &#xff08;3&#xff09;尽量减少类的协议中的消息。 &#xff08;4&#xff09;实现所有类都理解的最基本公…

问题?

1、java类空参构造器的作用&#xff1f; 构建对象时候所用的空参构造函数 2、static代码块与非static代码块的区别&#xff1a; 静态代码块&#xff0c;在虚拟机加载类的时候就会加载执行&#xff0c;而且只执行一次&#xff1b;非静态代码块&#xff0c;在创建对象的时候&…

【毕业设计】履带四足复合机器人

1.项目简介本项目中&#xff0c;履足式复合机器人拥有两种行进模式&#xff1a;四足行进模式、履带行进模式&#xff0c;应对不同场景及地形时能够切换形态。四足形态下整体总共拥有8个自由度DOF&#xff0c;单腿各具备2个自由度DOF&#xff0c;足端结构融入了履带机构&#xf…

UDT源码剖析(六):UDT::socket()过程代码注释

调用路线 UDT::socket()->CUDT::socket()->CUDTUnited::newSocket() 1 UDTSOCKET CUDT::socket(int af, int type, int) 2 { 3 // 如果垃圾收集没启动&#xff0c;那么这里自动调用startup 4 // 所以手动调用startup其实不是必须的&#xff0c;但是为了接受作者的风…

Exam化的软件项目管理

最近所做的工作是做一个公司产品的前期原型设计&#xff0c;这期间主要采用的是敏捷的Scrum开发方式&#xff0c;在一般的解释中认为每一个“疾跑”过程中&#xff0c;最主要的是交付一个可用的产品&#xff0c;Scrum在处理时间、资源和功能3点的平衡中&#xff0c;唯一可以牺牲…