这段时间以来,博客又被老夫遗忘在某个角落,要不是刀同学不时的催更,大有废弃之势。作为IT从业者(俗称码农),学习是不能停止的,那么写博客的习惯还是有必要坚持下去的。学习已经停顿了好些时间了,写不了技术博客那么先来回顾这阵子发生的事情好了。
libco源码学习(一)
协程,用一句话来描述就是用户态的轻量级线程。原有线程在调度上都是通过系统来完成的,因此每次切换阻塞都存在额外的开销。多线程在访问一些临界区资源时必须依靠锁等互斥机制。这也是多线程编程难的原因之一。而协程,则是将多协程之间的调度控制权交给了用户,协程拥有自己的寄存器上下文和栈。这使得在进行协程调度切换时,可以将寄存器上下文和栈保存到其他地方(where?),在切回来的时候,就可以恢复先前保存的寄存器上下文和栈,从而继续执行。多个协程其实仍是在单线程内执行,因此也不存在锁,系统调用,函数上下文切换等开销。
在并发编程中,线程是抢占式多任务,而协程则是协作式多任务。而由于抢占式调度执行顺序无法确定的特点,使用线程时需要非常小心的处理同步问题,稍有不慎就会出错。而协程则完全不存在这个问题。
可是在协程实现的细节上有些问题引起了我的兴趣:
- 可以知道,在函数调用过程中寄存器rbp,rsp(32位ebp,esp)等保存了栈底指针和栈顶指针,依靠这两个寄存器,程序可以在完成函数调用之后继续执行。那么在多个协程的情况下,如果协程自己的寄存器上下文和栈是独占还是共享的,那么在多协程情况下,寄存器上下文和栈的读写必然存在冲突,如何保证其正确性?
- 从以上分析来看,似乎每个协程都有一个自己的独立的寄存器上下文和栈显得更为合适且在实现上难度相对来说会容易不少,那么问题又来了,这样的数据保存在哪里?这块空间的大小应该就直接决定了该协程库所支持的并发协程数。
- 作为一个库来说,支持并发数如果上不去,必然没有优势。因此寄存器上下文和栈所占内存是否都是从堆上分配的?
- …
libco是目前微信后台大规模使用的C/C++协程库。号称2013年至今稳定运行在微信后台的数万台机器上。因此学习libco是深入协程技术细节的很好切入点。
简述函数调用过程栈和寄存器的操作
无论是面向过程还是面向对象编程,其中都少不了大大小小的函数和方法,A调用B,B调用C。那么有一个问题就是,A调用B的过程中,B执行结束,机器是如何知道该回到哪里继续执行的呢?这便引出了栈空间和寄存器的作用。
本文主要是记录一下我对函数调用过程中的大致流程,至于具体细节,可以参考以下博客。
rabbitmq客户端重构问题汇总
工作项目XX云中,由于涉及各模块间消息通信逻辑,放弃内部协议的情况下,已实现部分是将rabbitmq作为消息中间件,完成消息的生产和消费。项目编程语言是C++, rabbitmq官方客户端对于C语言的支持这一块,是由一个rabbitmq-c的开源库来完成的。阅读其源码,并结合实际项目中的使用情况,发现现有库有以下不足
- 心跳模块:客户端和server端需要进行一定的数据发送来实时感知链路状态。其中对于服务端来说,达到心跳超时时间之后,会向客户端发送一个心跳包,然后在下一个心跳超时时间之内,只要客户端有任何类型的数据发送至服务端,服务端就可以判断出链接状态的正常,否则服务端在没有收到任何数据时,会认为链路异常,从而主动关闭链路。现有开源库中对于收到服务端心跳包之后,并不会发送任何数据,因此在业务不频繁时,很有可能导致服务端关闭链路。
- 底层网络IO交互使用同步模式,阻塞用户线程且性能表现不佳。
基于以上原因,老夫和另外两名同事近期的工作重点就是对rabbitmq-c端进行重构。
貌似有点偏题,本文不是记录重构工作(PS.重构工作基本已经完成,第一个版本已具备基本功能),而是为了记录在开发测试过程中遇到并且解决的问题,以便帮助记忆。
Effective C++(三)
C++程序中最常使用的资源就是动态分配内存,但内存只是你必须管理的众多资源之一。其他常见的资源还包括文件描述符、互斥锁、图形界面中的字型和笔刷、数据库连接、以及网络socket。无论哪一种资源,当不再使用它时,必须将它还给系统。
尝试在任何运用情况下都确保以上所言,是件困难的事。但当你考虑到异常、函数内多重回传路径、程序维护员改动却没有充分理解随之而来的冲击。态势就很明显了:资源管理的特殊手段还不很充分够用。