1.SWD协议分析(附SWD离线源码)
2.OkHttp3源码详解之 okhttp连接池复用机制(一)
3.Linux时间子系统之:时钟源
4.深入理解 RxJava2:Scheduler(2)
5.数据库连接池之Hikari
SWD协议分析(附SWD离线源码)
SWD协议分析内容
SWD协议的基本信息比特序,即数据传输顺序为最低有效位优先,闲置闲置先传输低位数据,源码源码后传输高位数据。时间时间例如,闲置闲置对OK的源码源码天使之翼源码ACK响应数据为0b,先传输低位1,时间时间再传输高位0。闲置闲置
SWD的源码源码传输闲置状态为空闲周期,主机通过将SWDCLK时钟拉低来代表空闲时期。时间时间
ARM SWD采用单条双向数据连接线(SWDIO),闲置闲置为了防止主机与设备间的源码源码竞争,在传输方向变化时需要线路周转,时间时间此期间主机与设备均不驱动数据线,闲置闲置数据线状态不确定。源码源码周转时间长度由DLCR寄存器的TURNROUND位控制,默认为一个时钟周期。
在数据传输过程中,SWD使用偶校验,源码01011001传输数据中为1的个数为偶数则结果为0,否则为1。
数据基本传输流程包括数据传输方向和开始条件。ORUNDETECT标志位代表超时检测模式,该模式允许长时间高吞吐量连接,上电后默认禁用。数据传输步骤包括写请求和读请求,写请求在ACK阶段和数据传输阶段有一个周转期,读请求在数据传输阶段后存在周转期。
数据包请求后始终为转换时间,此时主机和目标均不驱动线路。ACK响应包含转换时间,仅在发生READ事务或接受WAIT或FAULT确认时需要。DATA传输包含转换时间,仅在READ事务中存在。
数据传输完毕后,主机需进行操作。SWD寄存器介绍包括SW-DP状态机、difflib源码SW-DP寄存器和SW-AP寄存器。状态机有内部ID代码,目标读取前状态机不工作。APnDP值决定访问这些寄存器。
AHB-AP具有位AHB-DP寄存器,地址宽度为6位,最多达字节或字节。
SWD协议的操作包括成功写入和读取操作。写入操作在主机接收到OK的ACK响应后立即开始数据传输,无需周转期。读取操作在数据传输完毕后存在周转期。
从JTAG切换到SWD操作涉及位JTAG到SWD选择序列,包括读取芯片ID、清除错误标志位和使能AP调试。读取MCU任意寄存器需发送两次读操作或一次读操作后发送一次读RDBUFF寄存器操作。写入MCU任意寄存器需参考相关文档。
具体操作流程和更多细节可参阅相关文档资料和源码。附件包含ARM调试接口架构规范和DAPProg源码。pyrdown 源码
OkHttp3源码详解之 okputation 和 io。
NewThreadWorker 在 computation、io 和 newThread 中都有涉及,下面简单了解一下这个类。NewThreadWorker 与 ScheduledThreadPoolExecutor 之间是一对一的关系,在构造函数中通过工厂方法创建一个 corePoolSize 为 1 的 ScheduledThreadPoolExecutor 对象并持有。
ScheduledThreadPoolExecutor 从 JDK1.5 开始存在,这个类继承于 ThreadPoolExecutor,支持立即、延时和周期性任务。但是注意,在 ScheduledThreadPoolExecutor 中,maximumPoolSize 参数是无效的,corePoolSize 表示最大线程数,且它的队列是无界的。这里不再深入探讨该类,否则会涉及太多内容。
有了这个类,bceloss 源码RxJava2 在实现 Worker 时就站在了巨人的肩膀上,线程调度可以直接使用该类解决,唯一的麻烦之处就是封装一层 Disposable 的逻辑。
ComputationScheduler 是计算密集型的 Scheduler,其线程数与 CPU 核心数密切相关。当线程数远超过 CPU 核心数目时,CPU 的时间更多地损耗在了线程的上下文切换。因此,保持最大线程数与 CPU 核心数一致是比较通用的方式。
FixedSchedulerPool 可以看作是固定数量的真正 Worker 的缓存池。确定了 MAX_THREADS 后,在 ComputationScheduler 的构造函数中会创建 FixedSchedulerPool 对象,FixedSchedulerPool 内部会直接创建一个长度为 MAX_THREADS 的 PoolWorker 数组。PoolWorker 继承自 NewThreadWorker,但没有任何额外的代码。
PoolWorker 的使用方法是从池子里取一个 PoolWorker 并返回。但是需要注意,每个 Worker 是独立的,每个 Worker 内部的任务是绑定在这个 Worker 中的。如果按照上述方法暴露 PoolWorker,会出现两个问题:
为了解决上述问题,需要在 PoolWorker 外再包一层 EventLoopWorker。EventLoopWorker 是一个代理对象,它会将 Runnable 代理给 FixedSchedulerPool 中取到的 PoolWorker 来调度,并负责管理通过它创建的任务。当自身被取消时,会将创建的任务全部取消。
与 ComputationScheduler 恰恰相反,IoScheduler 的线程数是无上限的。这是因为 IO 设备的速度远低于 CPU 速度,在等待 IO 操作时,CPU 往往是闲置的。因此,应该创建更多的线程让 CPU 尽可能地利用。当然,并不是线程越多越好,线程数目膨胀到一定程度会影响 CPU 的效率,也会消耗大量的内存。在 IoScheduler 中,每个 Worker 在空置一段时间后就会被清除以控制线程的数目。
CachedWorkerPool 是一个变长并定期清理的 ThreadWorker 的缓存池,内部通过一个 ConcurrentLinkedQueue 维护。和 PoolWorker 类似,ThreadWorker 也是继承自 NewThreadWorker。仅仅是增加了一个 expirationTime 字段,用来标识这个 ThreadWorker 的超时时间。
在 CachedWorkerPool 初始化时,会传入 Worker 的超时时间,目前是写死的 秒。这个超时时间表示 ThreadWorker 闲置后最大存活时间(实际中不保证 秒时被回收)。
IoScheduler 中也存在一个 EventLoopWorker 类,它和 ComputationScheduler 中的作用类似。因为 CachedWorkerPool 是每隔 秒清理一次队列的,所以 ThreadWorker 的存活时间取决于入队的时机。如果一直没有被再次取出,其被实际清理的延迟在 - 秒之间。
熟悉线程的读者会发现,ComputationScheduler 与 IoScheduler 很像某些参数下的 ThreadPoolExecutor。它们对线程的控制外在表现很相似,但实际的线程执行对象不一样。这两者的对比有助于我们更深刻地理解 Scheduler 设计的内在逻辑。
Scheduler 是 RxJava 线程的核心概念,RxJava 基于此屏蔽了 Thread 相关的概念,只与 Scheduler/Worker/Runnable 打交道。
本来计划继续基于 Scheduler 和大家一起探讨 subscribeOn 与 observeOn,但考虑到篇幅问题,这些留待下篇分享。
感谢大家的阅读,欢迎关注笔者的公众号,可以第一时间获取更新,同时欢迎留言沟通。
数据库连接池之Hikari
作为数据库连接池的佼佼者,HikariCP因其卓越的性能而备受推崇,尤其在SpringBoot2.0以后成为了默认选用的连接池。它的配置参数如autoCommit、connectionTimeout等,如autoCommit默认为true,用于自动提交从池中获取的连接。connectionTimeout设定了最大等待时间,idleTimeout则控制连接在池中的最长闲置时间,两者共同确保了连接的有效管理。keepaliveTime确保连接的存活,而maxLifetime则设定连接的最长生命周期,建议用户设置以优化性能。minimumIdle用于维护连接池的最小空闲连接数,而maximumPoolSize则控制最大连接数,poolName则是用于标识池的唯一名称。
HikariCP的高性能主要源于其技术优化。首先,它采用FastList替代ArrayList,提高get和remove操作的效率。其次,通过预先初始化避免了同步处理,提升初始化速度。动态字节码生成技术使得连接创建更为迅速。连接获取时,HikariCP在threadLocal中进行缓存,降低了线程间的并发冲突。同时,HikariCP设计目标在于减少锁竞争,确保在高并发环境中的稳定表现。关于更深入的解析,可以参考《非正经程序员:Spring Boot中使用Hikari,给我整不会了》和《数据库连接池之Hikari源码解析 - Lucky帅小武 - 博客园》等文章,以及《Springboot 2.0默认连接池HikariCP详解(效率最高)》。