tokyo tyrant源码分析-总体设计

本文深入探讨了Tyrant服务器的多线程架构设计,包括主线程、工作线程及定时线程的功能与交互机制。主线程负责监听与分发任务,工作线程处理客户端请求,定时线程执行周期性任务。

 

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

总体设计

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

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

结构:

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

多线程。三类线程:

 

主线程(1个):

监听socket,将接收到的请求sockfd分发给工作线程,以及信号处理。

worker线程(thnum个,参数指定,默认为8):

从主线程得到请求sockfd,处理请求(二进制、HTTP、memcache协议)

timer线程(最多8个):

do_slave (1个):

更新从库。定期(1s)向master请求更新数据日志,用来更新自己的数据库

do_extpc (参数指定,默认0个):

script extension. 提供对脚本和一些命令的支持

 

线程间联系:

主线程通过全局queue把accept到的请求sockfd传递给worker线程;

主线程捕捉信号,设置对应的全局变量。worker线程和timer线程周期性的检查全局变量来获取通知。

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

实现的简单代码描述

(所有代码中错误处理均已被过滤)

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

主线程:

--------

 

解释:

前面省略的部分检查参数有效性, 函数注册(do_slave ...),deamonize等;

信号处理:

SIGINT、SIGTERM做相同处理,设置serv->term = true,这样其它线程检查到该变量的变化后就退出。(信号捕捉函数不直接处理退出而只是设置全局变量,是一种多用的技巧。好处除了保持捕捉函数简洁,还能提供更好的灵活性:线程实现可以选择只在自己"愿意"的地方才检查该全局变量进而做相应处理,保证一些不能被打断的流程的完整性);

SIGHUP一是设置serv->term = true,让所有线程退出;二是设置g_restart = true,让while循环再次执行,启动所有其它线程。除了重启线程,它还重新打开日志文件。(tyrant没配置文件);

SIGPIPE忽略;

SIGCHLD捕捉,但捕捉函数什么也不做。

 

ttservstart创建worker线程和timer线程,统一accept用户请求并用全局queue将它们分发给worker线程:

解释:

创建监听socket:本地使用UNIX域协议(只需本机通信时使用。通过指定参数 -port 为一个小于1的数,比如0)以获得更好的性能,远端使用TCP协议;

创建thnum个worker线程和若干个timer线程 (pthread_create);

在循环中等待请求的到来。通过线程共享的数据结构queue来分配请求任务,queue中放置的是请求sockfd,访问前加互斥锁,push任务后用信号通知worker线程;

一次完整的处理后才检查是否收到信号(while(!serv->term);

主线程退出前要广播信号通知worker线程和timer线程是因为:

SIGTERM、SIGINT捕捉函数只是设置serv->term为true;

这时worker线程可能正在pthread_cond_timedwait等待serv->qcnd,(200ms),即正等待主线程给它分配任务;

timer线程是定期执行的(1s),它现在可能正在周期里。

虽然它们都可以在超时后(200ms,1s)发现到serv->term被设置进而退出,但这样的等待一段时间显然并不是最好。这里直接广播信号让它们马上退出阻塞函数。

 

 

这就是主线程的结构,很简单

 

 

 

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

worker线程:

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

worker从全局queue取请求sockfd并处理它们:

解释:

首先禁止线程结束请求,一次流程后才打开测试。也就是,不允许在流程中终止线程,不然会带来不完整性;

从全局queue取任务fd流程:

给全局queue加上互斥锁

如果上次成功取到fd(empty == false,即上次取时queue不为空),这次直接取

否则等待主线程发信号。不管是收到信号还是超时,都试着去从queue取fd

如果成功取到fd,do task

如果失败,设置标志(empty = true,这次取时queue为空),表示这次没取到fd

解锁

对fd读写的处理用TTSOCK做了封装,它底层一次从fd读取大块数据放入内部buffer(减少网络请求次数),但对上层提供一次读一个字节、一次读指定数目字节的API,方便上层开发。在"tyrant分析-编程小技巧"里有对它的详细描述。

 

补充说明:

原则上无碍对"总体设计"理解的代码全部去除,这里保留(1)是想说明,tyrant里大量使用了这种线程编程技术:开始时disable掉其它线程可能的取消该线程的请求,等一次流程结束后再打开测试是否有请求。目的是保护流程的完整性。

tyrant大量使用的另一个线程编程技术是在对某个资源的处理前pthread_cleanup_push资源释放函数,处理完后再pop。它相当于面向对象里"析构"的意思,确保资源的释放。这里没列出对应的代码,以后的"总体设计"里也都不会列出这些技术细节。

 

do_task分析请求的格式,根据请求协议和请求命令做相应处理:

解释:

do_task就是做三种协议的用户请求处理:

tt自己的二进制协议:第一个字节为TTMAGICNUM(0xc8)

memcache协议:   "get|set|add|... ..."

http协议:             "GET|PUT|DELETE|... HTTP/1.x ..."

三种协议只是格式不同,提供的服务一致:

get:  得到请求key对应的value

put:  先更新日志(ulog),再更新db

...

当然,http,memcache只是"外部"协议,tyrant只对它们提供一些"对外"服务,如get,put等。tyrant自己的"内部"二进制协议则支持更多的命令,比如主从复制(do_repl)。

get、put等底层实现是属于cabinet部分,会在"cabinet分析"部分详细描述

传输数据格式是tt自定义的,学习的意义不大,格式也很简单,比如它一般的格式是"ksiz + vsiz + key + value",其中没有'+',是紧挨的,因为siz长度是知道的,所以可以解析。当然还有一些有细微差别的格式。"tyrant分析-主从复制实现"里详细描述了其中一种协议的格式。

 

-------------
timer线程:
-------------
ttservtimer提供"定时执行"功能,它按timers提供的频率定期调用它们,这样timers只需要专注实现自己的功能:
解释:
(1)将timer函数的频率时间分割出整数和小数部分,并加上当前时间,作为等待超时时间。do_slave的频率是1秒。
(2)只有在一种情况下才会收到信号tcnd,那是在主线程退出时。这时不执行do_timed ,直接进入下个循环,检查到serv->term为true(被信号捕捉函数设置),退出。
---------------------
timer之do_slave:
---------------------
do_slave用于slave端,它和master建立socket连接,请求更新内容并用之更新自己,实现主从复制:
解释:
slave把上次更新到的时间rts放在文件里。每次更新就是从文件取rts,和master建立连接,循环请求到数据并用它们更新自己的ulog和db,然后更新rts文件。 master中负责处理请求的是do_task函数中的do_repl
slave-master的具体实现请参见"tyrant分析-主从复制实现"。

 

内容概要:本文是一篇关于使用RandLANet模型对SensatUrban数据集进行点云语义分割的实战教程,系统介绍了从环境搭建、数据准备、模型训练与测试到精度评估的完整流程。文章详细说明了在Ubuntu系统下配置TensorFlow 2.2、CUDA及cuDNN等深度学习环境的方法,并指导用户下载和预处理SensatUrban数据集。随后,逐步讲解RandLANet代码的获取与运行方式,包括训练、测试命令的执行与参数含义,以及如何监控训练过程中的关键指标。最后,教程涵盖测试结果分析、向官方平台提交结果、解读评估报告及可视化效果等内容,并针对常见问题提供解决方案。; 适合人群:具备一定深度学习基础,熟悉Python编程和深度学习框架,从事计算机视觉或三维点云相关研究的学生、研究人员及工程师;适合希望动手实践点云语义分割项目的初学者与进阶者。; 使用场景及目标:①掌握RandLANet网络结构及其在点云语义分割任务中的应用;②学会完整部署一个点云分割项目,包括数据处理、模型训练、测试与性能评估;③为参与相关竞赛或科研项目提供技术支撑。; 阅读建议:建议读者结合提供的代码链接和密码访问完整资料,在本地或云端环境中边操作边学习,重点关注数据格式要求与训练参数设置,遇到问题时参考“常见问题与解决技巧”部分及时排查。
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值