something_about_thread_safety

0x00 | 基本意义 当某个功能在多线程环境中被调用时,能够正确地处理多线程之间的共用变量,使程序能够按照预期正确执行。 如果一个功能(比如函数)在执行过程中需要修改一些公共变量,而且其功能是连续的,这一次的功能会受到上一次执行后对公用变量的修改的影响。 也就是说这个功能是受调用顺序影响的。 那么这个功能就不是线程安全的。 因为在多线程环境下,无法确定线程间调用功能的顺序。各个线程将会相互干扰。 0x01 | 锁 常见的就是mutex,互斥锁。 这是一种十分暴力的解决方案,简单易用,但是容易让程序退化回单线程。 0x02 | 原子操作 就目前而言,原子操作已经上升为CPU的一套指令集了。 原子操作通过硬件电路实现了一套基本没有开销的线程安全实现方案。 C++标准库中提供了相关API

February 29, 2024 · 1 min · 19 words · IAKSH

something_about_dependency_injection

在复用代码时,尽量使用has-a(组合),而非is-a(public继承)。 一来has-a不会将基类的所有api保留在子类,避免了“鸵鸟非鸟”的问题。 二是子类能在逻辑上与实际的基类解耦。子类依赖接口,而不是实际的基类。 依赖注入(dependency inject,DI) 之前已经提过了,”子类“应当依赖一个固定的接口,而不是某一个指定的类。这样,子类的设计着力点就从依赖的具体类的设计转回了子类本身。 然而这样会带来一个额外的问题:接口是否应该定义如何初始化该类?综合而言,答案是否定的。但如果接口没有规定如何初始化,那么子类又应该如何初始化一个未知初始化方式的成员类实例呢? 答案是DI。让子类所依赖的这个类在子类的外部构造,在这之后使用子类的setter将其绑定到子类中。 至于这个被依赖的类具体如何在子类外部被构造,我目前的想法是做一个工厂模式。当然,还是得看实际情况,如果并不需要太过泛化,直接调用构造函数就好。 DI实际上将一个类的依赖顺序倒置了: 在不使用DI,直接在类中镶嵌其所依赖的类时,整个构造是从顶部开始的,由顶部逐渐向其所依赖的底部进行。这个过程是自动化的,而且几乎是固定死了的。它为我们带来便利的同时,向我们隐瞒了实际上的依赖顺序。 而DI将这个过程倒置了,在构造顶部的类之前,我们需要从最底部的依赖开始,手动的构建整个依赖体系。 从维基上抄的一部分关于DI的内容 注:编程语言层次下,“接收方”为对象和 class,“依赖”为变量。在提供服务的角度下,“接收方”为客户端,“依赖”为服务。 0x00 | 四个基本概念 服务:任何提供了某种功能的类 客户:使用服务的类 接口:客户不应该知道服务实现的细节,只需要知道服务的名称和API 注入器:负责把服务引入给客户,叫法有很多:Injector / Assembler / Container / Provider / Factory 依赖注入把对象构建和对象注入分开,因此创建对象的 new 关键字也可以消失了。 0x01 | 实现方式 建钩子注入(构造注入?):依赖由客户对象的构造函数传入 Setter注入:客户对象只能暴露一个能接收依赖的setter方法。 接口注入:依赖的接口提供一个注入器方法,该方法会把依赖注入到任意一个传给它的客户。客户实现一个setter接口,可设置依赖。 0x02 | 我的理解 DI实际上就是尝试使客户类的设计关注点回归到类本身,而非其所依赖的类。 认识到了一个新的词 ”关注点分离“。

February 29, 2024 · 1 min · 45 words · IAKSH