对操作系统的理解
了解操作系统首先需要知道它处于计算机中的一个什么样的地位,在哪一个层次。底层是硬件,与硬件相关联的是寄存器和IO之类的管脚,硬件可以接受外部的操作形成“中断”信号,这个信号统一传输到操作系统内核与硬件相关联的接口处,然后内核会判断选择哪个系统调用,通过内核和应用层的接口进行转义,决定调用应用层的哪个方法,最终实现和用户的交互。应用软件中的某个操作也同样可以反向影响到硬件设备的运行。以上提到的计算机和应用的交互都是基于操作系统的,操作系统是应用程序和底层硬件的纽带,内核是操作系统的核心组成部分,内核的系统调用方法是绝大多数应用程序需要直接或者间接调用的。操作系统还需要通过调度进程负责协调和调度多个进程以及通过“陷阱”确保操作系统运行的安全可靠。
系统调用
操作系统内核线程执行的方法是系统系统调用,一般是通过在应用层请求调用某个方法,然后在内核中由内核线程去实际调用它。系统调用包括一系列方法涉及到通信、IO、线程等。系统调用一般尽量追求精简,因为内核所能使用的内存空间是有限的,一般足够支持所有的功能即可,具体的功能实现可以在上层应用中完成。但是内核中方法的完备也有好处,那就是效率很高,内核的方法可以直接完成需要完成的工作,而不需要反复在用户模式和内核模式之间反复切换,于是,为了减少内存占用,目前使用的比较多的模型是利用面向对象的思想构建的模块化系统调用,处于和核心的系统调用是最基本的、最核心的系统调用,其余系统调用是针对具体功能模块实现的内核级方法,有较高的效率,但是它们并不全部加载,只在需要用到的时候加载为系统调用的一部分。关于系统调用,我们可以发现,Java程序中的方法部分都是间接调用了系统调用方法,比如创建线程,虚拟机中的用户态线程实际在内核中有创建的内核态线程,比如线程的挂起等操作实际上都是调用了内核态的线程,涉及到了用户态和内核态的切换。
用户模式及内核模式
在软件应用层中进程调用方法称为在用户模式下的调用,而进程在内核中调用方法则称谓内核模式,两个模式看似都是调用方法,实际上是有区别的。比如内核线程具有一些特权,比如一些涉及系统安全的方法,如果在用户模式下线程调用这些方法,容易造成操作系统的崩溃。在单CPU处理器下操作系统只能运行在一个模式下,那么如何区分当前操作系统运行在哪个模式呢?可以通过一个标志来区分,这个标志在用户模式下为0,在内核模式下为1。只有在标志表示当前运行在内核模式下时,才允许调用特权方法。这样的好处是避免在频繁的模式切换下方法调用出现混乱,避免了危及操作系统安全的事故发生。
操作系统中的进程和线程
调度:
每个进程有属于它自己的PCB,这是一个保存进程信息的代码块,它用来实现在进程之间调度或者切换时实现保存现场和恢复现场。在这里举一个例子,比如进程A在运行时发生了中断,需要运行一段进程B的代码,那么首先要做的事情就是保存现场,在PCB中保存记录线程A的程序计数器、数据等,然后把这个数据结构保存在系统的内存中供CPU调度;接下来读取进程B的PCB,恢复B的现场,然后执行一段代码,结束后再更新它的PCB并保存;最终恢复A的现场,继续执行进程A的代码。
线程的内存特点:
如果是进程是CPU调度的最小单元,那么线程是进程的最小单元。多个线程共享代码,数据(堆);但是它们都有独立的计数器和栈。
多线程相比多进程的优点:
最初在处理多任务时的方式是开多个进程去处理,但是这样效率很低下,开销也很大。线程相比就比较轻量级,也便于管理,处理并发请求,避免了频繁创建和销毁进程的开销。
操作系统的CPU调度策略
FCFS和SJF:
1.FCFS:先到先服务策略,一般进程会被存放在就绪队列中等待CPU的处理和调度,这个队列中存放的一般是进程的PCB。最先创建的进程一般会优先被CPU处理,它是非抢占式的,一般会等到当前进程被CPU处理完之后才会去处理下一个进程。这种方式相对来说比较简单,但是效率很低。
2.SJF:最短作业优先调度策略,这种算法是最佳的,它优先调用需要占用CPU时间最短的进程,平均等待时间是最少的。因为当把一个时间短的进程优先处理,短进程等待时间的减少大于长进程等待时间的增加,总体来说平均等待时间是减少的。
轮转法调度:
又称为时间片轮转的调度方法,每个进程都会被分配到一定的CPU时间,CPU从就绪进程队列首部开始执行进程,当进程的实际时间小于被分配给它的时间片时,会直接令CPU去处理下一个进程;而当它的时间大于时间片时,则会停止它的运行,移到队尾,CPU会执行下一个进程。这种方法的好处是CPU的利用十分高效率,且时可抢占的,不会让单个进程占据过多的CPU时间。
多处理器调度:
多个CPU下操作系统运行效率会高很多,每个处理器都有自己的进程队列,独立的处理着自己的作业。在多CPU下,需要注意避免冲突,比如一个进程仅能被归于一个CPU下处理。同时还需要尽量让一个进程仅在一个CPU下运行,这样可以避免缓存资源多销毁与重复创建。另外也尽量保证多个CPU实现负载均衡,提高效率。