1、 第 1 页 共 16 页 实用操作系统期末考试题型说明 2016 年 6 月 16 日 一、名词解释(共 5 题,每题 3 分,计 15 分) 通过 23 句话说明相关概念的基本定义。 二 、计算题(共 2 题,每题 15 分,计 30 分) 结合相应图表,根据题目要求,计算相应结果(给出详细计算过程,分步给分)。 三 、简答题(共 5 题,每题 6 分,计 30 分) 根据提问,对相关知识点进行总结,并作必要对比分析。 四 、程序分析题(共 2 题,每题 7 分,计 14 分) 根据相关代码框架,说明相应技术的实现原理与机制(不需要对代码细节做深入分析)。 五 、 程序 设计题 (共 1
2、题,计 11 分) 根据题目要求,给出相应的设计方案。 第 2 页 共 16 页 实用操作系统复习提纲 提示: 1)请根据以下提纲整理相关知识内容的要点,避免去死记硬背。 2)请不要简单地依据往年试题内容复习,否则后果自负。 第一讲: Linux 系统分析基础 1、什么是用户态和内核态及划分的必要性? 不区分的缺陷 用户直接修改操作系统数据 用户直接调用操作系统内部函数 用户直接操作外设 用户任意读 /写物理内存 区分意义:保护内核 禁止用户程序和底层硬件直接打交道 如果用户程序往硬件控制寄存器写入不恰当的值,可能导致硬件无法正常工作 禁止用户程序访问任意物理内存,否则可能会破坏其他程序的正常
3、执行 如果对核心内核所在的地址空间写入数据,会导致系统崩溃 2、 Linux 单内核、多模块的特点及其与微内核操作系统的主要区别。 Linux 是单内核、多模块系统 Linux 内核运行在单独的内核地址空间 所有操作系统功能作为一个模块实现在内核中 模块均运行在内核态,直接调用函数,无需消息传递 模块化设计、抢占式 (Linux 2.6 内核级抢占, Linux 2.4 用户级抢占 )、支持内核 线程及动态装载内核模块的能力 与 Unix 主要区别 Unix 也是单内核系统,但 Linux 汲取了微内核设计思想(基于模块定制内核) Unix 也是单内核系统 Windows NT 和 Mach
4、是微内核系统 只提供基础功能,其他功能通过服务实现 微内核被划分为多个独立过程,每个过程称为服务器 第 3 页 共 16 页 3、 可加载内核模块的概念,内核模块与 C 语言应用程序的主要差别。 加载内核模块 (Loadable Kernel Module)的概念 模块实际上是一种目标对象文件,没有链接,不能独立运行 其代码可以在系统运行时链接到系统中,作为内 核的一部分运行或从内核中取下,从而可以动态扩充内核的功能(不需要重新编译内核) 这种目标代码通常由一组函数和数据结构组成 C 语言程序 模块 运行 用户空间 内核空间 入口 main() module_init() 出口 无 modul
5、e_exit() 编译 gcc -c 编制专用 Makefule,并调用 gcc 连接 gcc insmod 运行 直接运行 insmod 调试 gdb kdbug, kdb, kgdb 等 第二讲:进程与线程 1、 Linux 2.4 及 2.6 进程系统堆栈结构特点及主要区别。 第 4 页 共 16 页 Linux 进程系统堆栈结构特点 8192( 213 )字节,两个页框 占据连续两个页框,且第一个页框起始地址为 213 的倍数 Linux2.4 进程系统堆栈结构特点 结构定义 (/include/linux/sched.h) Linux2.6 进程系统堆栈数据结构定义 (其定义了一个指
6、向 进程描述符的指针) Linux2.6 进程系统堆栈结构特点 第 5 页 共 16 页 两者区别: Linux2.4 进程描述符由 alloc_task_struct(), free_task_struct(), get_task_struct()进行管理 , Linux2.6 进程描述符由 slab 分配器动态生成 ; Linux2.4 进程系统堆栈栈底使用 struct task_struct 结构, Linux2.6 进程系统堆栈栈底使用新结构 struct thread_info,其定义了指向进程描述符的指针,占用更小的栈空间 2、 进程(组)相关标识符的含 义。 成员名: pid_
7、t pid 功能: 内核通过 pid 标识每个进程 pid 与进程描述符之间有严格的一一对应关系 成员名: pid_t tgid 功能: 标识进程是否属于同组,组 ID 是第一个组内线程(父进程)的 ID 线程组中的所有线程共享相同的 PID 3、 idle 进程。 系统引导进程( init_task)在引导结束后成为 cpu 0 上的 idle 进程,每个 cpu 上都有一个 idle 进程 , idle 进程不进入就绪队列 , 仅当就绪队列为空时 idle 进程才会被调度 。 4、 通用内核链表的设计特点及与双向链表的主要区别。 特 点: 链表结构作为一个成员嵌入到宿主数据结构内 链表结构
8、可放在宿主结构内的任何位置 一个宿主结构可有多个内核链表结构 避免为每个数据项类型定义自己的链表 通用内核链表不用为每个数据项定义链表。传统双向链表的指针记录节点的首地址,通用内核第 6 页 共 16 页 链表的指针记录链表的地址。 6、 “ RCU”的特点与作用。 特点: 以“ _rcu”结尾的宏 通过延迟写操作来提高同步性能 作用: RCU 常用来保护读操作占多数的链表与数组 7、 常用进程创建函数的主要差别及使用方法。 进程创建函数 pid_t fork(void); pid_t vfork(void); int clone(int (*fn)(void * arg), void *st
9、ack, int flags, void * arg); 关系差别 fork, vfork and clone 三者最终都会调用 do_fork 函数 。 Vfork()与 fork()功能相同,但 vfork()但不拷贝父进程的页表项。子进程只执行 exec()时, vfork()为首选。而对于 clone()是创建轻量级线程的。它是 fork()的推广形式,它允许新进程共享父进程的存储空间、文件描述 符和信号处 使用:(个人觉得略坑) do_fork(unsigned long c lone_flag, unsigned long stack_start, struct pt_regs *
10、regs, unsigned long stack_size, int _user *parent_tidptr, int _user *child_tidptr); 参数说明 clone_flag:子进程创建相关标志 stact_start:子进程用户态堆栈的地址,将用户态堆栈指针赋给子进程的 esp regs:从用户态 切换至内核态时保存用户堆栈到内核态的堆栈 stack_size:未使用(总设为 0) parent_tidptr:父进程用户态下的 PID 地址,若需父进程与新轻量级进程有相同 PID,则需设置CLONE_PARENT_SETTID child_tidptr :新建子进程
11、用户态下的 PID,若 需让新进程具有 同类进程的 PID,需设置CLONE_CHILD_SETTID 、 说明 vfork()创建的子进程与父进程共享地址空间 子 进程作为父进程的一个单独线程在其地址空间运行 子进程从父进程继承控制终端、信号标志位、可访问的主存区、环境变量和其他资源分配 子进程对虚拟空间任何数据的修改都可为父进程所见 父进程将被阻塞,直到子进程调用 execve()或 exit() 、 第 7 页 共 16 页 int clone(int (*fn)(void *), void *child_stack, int clone_flag, void *arg); 参数说明 f
12、n:待执行 的程序 child_stack:进程所使用的堆栈 clone_flag:由用户指定,可以是多个标志的组合 arg:执行 fn 所需的参数 功能 创建轻量级进程 (LWP)的系统调用 通过 clone_flag 控制 8.进程、用户线程、内核线程的主要区别。 进程: 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,被操作系统调度,一个系统资源的的集合。 用户线程: 存在于用户空间中,通过线程库来实现 线程创建和调度都在用户空间进行,以进程为单位调度 内核线程: 在内核空间内执行线程的创建、调度和管理 内核线程的创建和管理慢于用户线程的创建和管理 9、 为何 fork 系
13、统调用能返回两个不同的返回值。 第三讲:进程调度 1.Linux 2.4 及 2.6 进程调度体系、调度框架的特点及差别。 Linux2.4 的调度体系基于共享全局队列,其算法属于 O(n),开销是线性增长的。 Linux2.6 每个处理器都有独立的就绪进程队列,各个处理器可以并行运行调度程序来挑选进程运行,不同处理器上的进程可以完全并行地休眠、唤醒和上下文切换。 2.主动调度与被动调度的特点。 Linux2.4: 主劢调度:直接调用 schedule() 被劢调度:置位当前进程的 need_resched,和主劢调度相比,被打调度有一定的调度延时 Linux2.6: 第 8 页 共 16 页
14、 包含了 Linux 2.4 的调度时机,增加内核可抢占。 3.Linux 2.4 及 2.6 进程调度中优先级算法的设计。 优先级定义 静态优先级: priority( 070) 表示分配给进程的时间片 指明在被迫和其他进程竞争 CPU 之前,进程允许的最大时间片 只能由用户进行修改,不随时间而改变,一般通过 nice 设定 动态优先级: counter 进程拥有 CPU 时随时间不断减小 指明在这 个时间片中所剩余的时间量 当小于 0 时,标记进程重新调度 实时优先级: rt_priority( 199) 确定实时进程的调度顺序,较高权值进程优先于较低权值进程 非实时进程的优先级为 0,因
15、此实时进程总优先于非实时进程 2.4: 普通进程 基本思想:动态优先级调度 通过更新 counter 值,周期性修改进程优先级(避免饥饿) 基本过程 counter 变为 0 时,用 priority 对 counter 重新赋值 所有可运行状态进程的时间片都用完后才对 counter 重新赋值 进程运行过程中, counter 的减小为 其它进程提供运行机会 该机制相当于优先级在动态变化,所以称之为动态优先调度 实时进程 基本思想:静态优先级策略 counter 只用来表示该进程的剩余时间片 不作为衡量其是否值得运行的标准(与普通进程的区别) 调度设计的基本原则: 动态调整优先级及时间片长度
16、 2.6: 基于每个 CPU 分配时间片,取消全局同步和重算循环 每个处理器有两个数组:活动就绪进程队列和不活跃就绪进程队列 进程消耗完其“时间片”后,进入不活跃就绪进程数组中相应队列的队尾 当所有进程都“耗尽”其“时间片”后,交换活跃与不活跃就绪进 程队列数组,不需要任何其他的开销 每个数组中有 140 个就绪进程队列 (runqueue),每个队列对应于 140 个优先级的一个 通过位图标记队列状态 调度时,通过 find_first_bit()找到第一个非空的队列,并取队首进程 不管队列中有多少就绪进程,挑选就绪程的速度恒定,因此称为 0(1)算法 第 9 页 共 16 页 4.Linu
17、x 2.4 及 2.6 负载均衡机制的实现思路。 Linux2.4 的负载平衡基本策略:进程 p 被切换下来之后,如果还有 CPU 空闲,或者该 CPU 上运行的进程优先级比自己低,那么 p 就会被调度到那个 CPU 上 运行,内核使用该办法来实现负载平衡。 Linux2.6 的基本策略:采用相对集中的负载平衡方案,分为“推”和“拉”两类操作 “拉”操作:当某个 CPU 负载过轻、而另一 CPU 负载较重时,系统会从重载 CPU 上“拉”进程过来。有两种调用方式:“忙平衡”:当前 CPU 不空闲;“空闲平衡”:当前 CPU 空闲。 “推”操作:在系统启动时自动加载(每个 CPU 一个),并将自
18、己设为 SCHED_FIFO 的实时进程,定期检查 migration_queue 中是否有请求等待处理,若没有,就在 TASK_INTERRUPTIBLE 中休眠,直至被唤醒后再次检查。 5.Linux 2.6 如何体现交互式进程优先的。 内核有四处对交互式进程的优先考虑 sleep_avg 交互式进程因为休眠次数多、时间长, sleep_avg 也会相对更大一些 interactive_credit 记录进程的交互程度 判断进程是否是交互式进程 TASK_INTERACTIVE()宏 就绪等待时间的奖励 对交互式进程的优先级奖励 系统通过 HIGH_CREDIT() 累积方式完成奖励 当进
19、程从 CPU 切换下来时,如果是交互式进程,则它参与优先级计算的 运行时间会比实际运行时间小,以此获得较高的优先级 交互式进程处于 TASK_UNINTERRUPTIBLE 状态下的休眠时间也会叠加到 sleep_avg 上,从而获得优先级奖励 6.内核抢占、用户抢占的实现机制及差异;何种情形下不允许内核抢占。 当进程位于内核空间时,有一个更高优先级的任务出现时,如果当前内核允许抢占,则可以将当前任务挂起,执行优先级更高的进程。 第四讲:进程通信 1.常用进程通信方式在设计目标、使用场景的主要区别及相关函数的使用方法。 信号( signal):进程或内核使用信号机制通 知其他进程发生某一事件
20、第 10 页 共 16 页 管道( pipe)及有名管道( named pipe):用于具有亲缘关系的进程间通信 相关代码略(太多。) 相关函数看 ppt,看完估计想死的心也有了 _ 信号安装函数: signal(), sigaction() 信号发送函数: kill(), sigqueue(), raise(), alarm(), setitimer(), pause() 信号集操作函数: sigemptyset(), sigfillset(), sigaddset(), sigdelset(), sigismember() 。 2.可靠信号及非可靠信号的特点、主要区别, 信号处理机制的内核
21、实现机制。 不可靠信号 信号值小于 SIGRTMIN 进程每次处理信号后,将信号响应函数设置为默认动作,需调用 signal() 重新安装信号 非实时信号都是不可靠信号,不支持排队,信号可能丢失 可靠信号 信号值介于 SIGRTMIN 和 SIGRTMAX 之间 新信号安装函数 sigaction()和信号发送函数 sigqueue() 实时信号都是可靠信号,支持排队 3.IPC 资源、 IPC 键、 IPC 标示符的定义。 IPC 资 源 表示单独的消息队列、共享内存或信号量集合 。 IPC 键 IPC 对象的外部表示,可由程序员选择。 如果键是公用的,则系统中所有进程通过权限检查后,均可找
22、到和访问相应 IPC对象。 如果键是私有的,则键值为 0。(每个进程都可建立一个键值为 IPC_PRIVAE 的私有 IPC 对象。) IPC 标识符 由内核分配给 IPC 对象,在系统内部唯一 IPC 对象标识符的获取: XXXget() 将 IPC 键传递给以 sys_打头的内核函数,并为用户分配一个与 IPC 对象相对应的数据结构。 返回一个 32 位 IPC 标识符,进程使 用此标识符对该资源进行访问 4.IPC 资源内核结构设计的特点。(真没理解,不知道对不对) 设计了:消息队列:( msgid_ds ) 16 个。共享内存:( shmid_ds ) 4096 个。信号量 ( semid_ds): 128 个 5.不同 IPC 进程通信机制在内核结构设计上的异同点。 6.可撤销信号量的定义及其内核实现机制。