linux可以借鉴的设计思想(笔记)

来源:互联网 发布:redis mysql完美结合 编辑:程序博客网 时间:2024/05/18 13:11

1C语言嵌入结构

  • 实现继承(典型的Kobject);

  • 封装:通过结构体对对一类信息包装,便于后续扩展、升级,即使信息只有一个简单数据,如kref;对结构体成员的访问要通过函数来实现成员封装,使得结构体面向功能服务,易于扩展

  • 抽象:通过在结构体内嵌入特殊用途的结构体(可包含相关具体函数)实现抽象设计,可以将对象看作某类对象,看作实现某种服务抽象,类似C++virtual。如cpu均衡部分,就绪队列中,嵌入与均衡相关的结构及处理,上层在得到均衡通知时,任务下放sched_class具体处理。另一个例子是调度,他处理的是可调度实体(sched_entity),可以是进程、也可以是进程组(不同用户)。

2、数据结构:

  • 散列表在linux上的实现:定义散列区间(一般不能太大),确定数组,在每一个数组项上,通过双链表方式存储散列项相同的数据项,而散列函数的理想是等概率分布。

  • 红黑树:通过深度优先搜索(DFS)生成有序队列,如调度的等待时间,通过深度优先,生成按照等待时间排序的队列,在调度时,只调度最左侧地下的一个就ok。(时间复杂度为对数)

  • 双向循环链表:

  • 位图辅助索引:

3、副本与写时复制技术:

  • 通过复制副本获取父对象的所有资源,并使得修改副本是一个独立对象,从而不影响父对象。(进程结构:task_struct,命名空间nsproxy);

  • fork复制了task_struct,实际上就有了2个完全相同的进程,并且都运行到了同一个地址上。在linux上进程与线程的不同仅体现在共享资源的不同上,每个线程都有唯一的task_structforkclone只有细微的差别。

4、结构相关:

  • 宏定义:通过宏定义进行与结构相关操作,隐藏具体细节,便于移植;如结构体中,变量相对位置不能假定,应采用宏定义的方式计算得到(container_of),如一个数据不同位代表不同含义;

  • 小的内联函数:提供封装性,且效率很快

5、合理的goto结构:

  • 虽然混乱的使用goto容易打乱程序的结构,备受诟病,但是在初始化时按照以下匹配的方式()使用goto,代码相当简洁:

  • if(A)

gotooutA;

if(B)

gotooutB;

if( C)

gotooutC;

...

outC:...

outB:...

outA:...

6、合理提高效率:

  • 不能对正在运行的进程进行迁移

  • 设备上下文恢复时考虑部分保存与部分恢复

  • 块设备数据读取请求合并、预测读取策略

  • 有以上足可见对性能追求之极致

7设备控制的4种方式,在类似问题上综合考虑能否提供通用模版支持扩展:

  • 通过通用文件操作,传输数据,根据数据的特殊性(控制指令),实现设备控制,少数设备,基本废弃

  • 添加一系列特有控制函数(不同于常规文件系统):不利于扩展,未采用。

  • 添加ioctl,就是命令函数,与invoke等类似:稍显过时,应用层和内核的命令要匹配修改,麻烦

  • sysfs:统一的属性修改方式,易于扩展。

8、中断处理机制:

  • 修改全局状态的情况:先保存要修改的状态,修改为新状态,使用新状态处理,恢复原状态;(例如在绘图相关程序中,对绘图设备属性更改,如果没有采用这种方式处理,往往运行结果随机出现不正常,且不具有重现性)

  • 将必要的内容放在中断处理程序中,将非必要的处理放在下半部分,提高性能;(比如在绘图的onpaint中,是不是里面只包含了必要的绘图,在达不到要求的帧率条件下,是否可以把不必要的内容放在外面,双缓冲绘图,实际可看做将绘图处理部分放在主绘图线程之外的一种做法,它的主线程只负责copy帧内容)

9、对象生存期管理:

  • 引用计数方式

  • 谁分配谁释放原则

10、设计模式理念:

  • 块设备驱动中bio对象封装读写请求,ioctl:借鉴了命令模式的理念

  • VFS中的file_operations中的open:按照普通文件、特殊设备文件的顺序处理(如果不是该我处理的转下去),暗含了责任链的思想

  • io读写请求调度(分离的功能和实现方式):可归类策略模式;

  • VFS:为不同的文件系统提供统一的外部接口,可作为不同类型文件系统之间的中介或者也可说是适配器。

11、通用处理默认、专用处理修改的技巧,简化开发:

  • 各种标准接口中大部分都提供了通用的处理,如file_operation的接口基本都有默认处理函数

  • html中可以将主流风格定义样式,默认适用于整个html显示元素,同时支持对个别元素的外观特征的修改,一般通用部分可通过样式工厂设置、处理;

12、回调:

  • 回调就是预先告诉第三方你可以接收消息或者事件的接口,典型的有事callme”,与中断本质上是一会事。

  • 回调用的场合:架构设计。在C中一般在相应数据结构中定义回调函数指针,初始化时赋值,如驱动中file_operation定义的架构。

  • 广义的回调不限于函数本身:如浏览器最初只定位为html界面元素的显示,通过引入脚本语言来增强浏览器不支持的能力,可看做浏览器提供回调接口,扩充浏览器本身没有的算法处理能力。

13、进程/线程/用户进程/内核线程:

  • 进程与线程:linux不提供单独的线程支持,线程也是一种进程,只不过与别的进程在clone时通过设置共享标志,与其他进程共享某些资源(包括地址空间),有独立的task_struct

  • 内核线程与普通线程:普通进程或者线程有独立的虚拟地址空间,而内核线程没有独立的虚拟地址空间,都在内核地址空间中运行。

14字符设备驱动与块设备驱动:

  • 区别:从架构上讲,两者区别仅限于在块设备驱动中增加了缓冲层(需要增加请求队列管理和调度的部分),提高性能;

  • 联系:向上(VFS)提供统一的文件操作接口;

15、抢占与中断:

  • 抢占:属于调度的范畴、可发生在用户空间或者内核空间,分属内核抢占和用户抢占,特点都是发生在某种事件发生或结束时,有更高优先级的进程需要优先运行;在时间上属于准实时;

  • 中断:属于打断当前执行的情况,在时间上属于实时;

16、用户空间切换内核空间的两种方式:

  • 硬件中断(不可睡眠、抢占);

  • 系统调用(是一种软中断,可睡眠、抢占,必须保证代码可重入)

17、中断:

  • 申请中断号(有一部分中断号是固定的如时钟,其他的如PCI上的设备,可动态申请,共享使用(设备多,中断号少))

  • 定义中断处理函数,即注册时的回调函数

  • 中断注册函数可睡眠(具体为内核内存分配函数可睡眠),因此不能在不可睡眠的地方进行中断注册,一般在设备初始化或者设备与驱动建立连接时进行,确保设备已经初始化才能注册中断;

  • 使用完后,应该释放中断处理程序、甚至禁用中断线

18、为什么在中断处理程序中不能阻塞或者睡眠?

  • 因为中断处理程序不被进程调度程序管理,阻塞后,无法通过调度恢复。

19、中断处理程序/下半部处理程序

  • 数据的收集/数据的处理使用不在同一线程:保证可靠的接收数据;如入库

  • 计算/显示分属不同线程:确保显示不死机、响应慢;

  • 目的是调和两种矛盾。

20linux操作系统运行的两种时序:

  • 内核作为一个独立运行体,按照顺序执行的方式执行,调度不过是执行过程中的一种执行路径的选取,进程是内核管理执行体的插件方式;

  • 中断执行:由硬件触发,打破当前执行序列的执行;

21、系统调用

系统调用:是用户程序访问系统资源或者使用系统的唯一通道,安全检查,提高可靠性;

实现机制:软中断(int80);

实现方式:system_call(系统调用号,参数表)跟invoke类似,属于命令模式范畴

22、软中断、tasklet、工作队列比较

软中断、tasklet:是运行在中断上下文中的,都是软中断,tasklet是对软中断的一种同步化、序列化封装、使用简化封装;不可以调度、不可以睡眠;

工作队列:是运行在进程上下文的,是有进程控制块的内核线程;可以调度、可以睡眠;


原创粉丝点击