操作系统
操作系统基础
操作系统主要有哪些功能
从资源管理的角度来看,操作系统有 6 大功能:
- 进程和线程的管理:进程的创建、撤销、阻塞、唤醒,进程间的通信等。
- 存储管理:内存的分配和管理、外存(磁盘等)的分配和管理等。
- 文件管理:文件的读、写、创建及删除等。
- 设备管理:完成设备(输入输出设备和外部存储设备等)的请求或释放,以及设备启动等功能。
- 网络管理:操作系统负责管理计算机网络的使用。网络是计算机系统中连接不同计算机的方式,操作系统需要管理计算机网络的配置、连接、通信和安全等,以提供高效可靠的网络服务。
- 安全管理:用户的身份认证、访问控制、文件加密等,以防止非法用户对系统资源的访问和操作。
用户态和内核态
什么是用户态和内核态?
根据进程访问资源的特点,可以把进程在系统上的运行分为两个级别:
- 用户态 User Mode
用户态运行的进程可以直接读取用户程序的数据,拥有较低的权限。
当应用程序需要执行某些特殊权限的操作,例如读写磁盘、网络通信等,就需要向操作系统发起系统调用请求,进入内核态。 - 内核态 Kernel Mode
内核态运行的进程几乎可以访问计算机的任何资源,包括系统的内存空间、设备、驱动程序等,不受限制,拥有非常高的权限。
当操作系统接收到进程的系统调用请求时,就会从用户态切换到内核态,执行相应的系统调用,并将结果返回给进程,最后再从内核态切换回用户态。
内核态相比用户态拥有更高的特权级别,因此能够执行更底层、更敏感的操作。不过,由于进入内核态需要付出较高的开销(需要进行一系列的上下文切换和权限检查),应该尽量减少进入内核态的次数,以提高系统的性能和稳定性。
为什么要有用户态和内核态?只有一个内核态不行么?
- 在 CPU 的所有指令中,有一些指令是比较危险的比如内存分配、设置时钟、IO 处理等,如果所有的程序都能使用这些指令的话,会对系统的正常运行造成灾难性地影响。因此,我们需要限制这些危险指令只能内核态运行。这些只能由操作系统内核态执行的指令也被叫做 特权指令 。
- 如果计算机系统中只有一个内核态,那么所有程序或进程都必须共享系统资源,例如内存、CPU、硬盘等,这将导致系统资源的竞争和冲突,从而影响系统性能和效率。并且,这样也会让系统的安全性降低,毕竟所有程序或进程都具有相同的特权级别和访问权限。
因此,同时具有用户态和内核态主要是为了保证计算机系统的安全性、稳定性和性能。
用户态和内核态是如何切换的?
用户态切换到内核态的3种方式:
- 系统调用 Trap
用户态进程 主动 要求切换到内核态的一种方式,主要是为了使用内核态才能做的事情,比如读取磁盘资源。
系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现。 - 中断 Interrupt
当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。
比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。 - 异常 Exception
当 CPU 在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
在系统的处理上,中断和异常类似,都是通过中断向量表来找到相应的处理程序进行处理。区别在于,中断来自处理器外部,不是由任何一条专门的指令造成,而异常是执行当前指令的结果。
系统调用
什么是系统调用?
我们运行的应用程序基本都是运行在用户态,如果我们需要调用操作系统提供的内核态级别的功能,这就要用到系统调用了。
也就是说,在我们的应用程序中,凡是与系统级别的资源有关的操作(如文件管理、进程管理、内存管理等),都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。
这些系统调用,按功能大致可分为如下几类:
- 进程管理
进程的创建、撤销、阻塞、唤醒,进程间的通信等功能。 - 内存管理
完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。 - 文件管理
完成文件的读、写、创建及删除等功能。 - 设备管理
完成设备(输入输出设备和外部存储设备等)的请求或释放,以及设备启动等功能。
系统调用和普通库函数调用非常相似,只是系统调用由操作系统内核提供,运行于内核态;而普通的库函数调用由函数库或用户自己提供,运行于用户态。
总结:系统调用是应用程序与操作系统之间进行交互的一种方式,通过系统调用,应用程序可以访问操作系统底层资源,例如文件、设备、网络等。
系统调用的过程
- 用户态的程序发起系统调用,因为系统调用中涉及一些特权指令(只能由操作系统内核态执行的指令),用户态程序权限不足,因此会中断执行,也就是 Trap(Trap 是一种中断)。
- 发生中断后,当前 CPU 执行的程序会中断,跳转到中断处理程序。内核程序开始执行,也就是开始处理系统调用。
- 内核处理完成后,主动触发 Trap,这样会再次发生中断,切换回用户态工作。
处理器管理
进程和线程
进程间的五种通讯方式
- 管道pipe
- FIFO(有名管道)
- 消息队列
- 信号量
- 共享内存
- 套接字socket
- 文件和记录锁定(UNIX中)
为什么要使用多线程?
进程是系统资源分配的最小单位;线程是进程划分成的更小的运行单位,共享进程的资源比如内存空间、文件句柄、网络连接等,是CPU执行的最小单位。
- 单核时代
单核时代多线程主要是为了提高单进程利用 CPU 和 IO 系统的效率。
假设只运行了一个 Java 进程的情况,当我们请求 IO 的时候,如果 Java 进程中只有一个线程,此线程被 IO 阻塞则整个进程被阻塞。CPU 和 IO 设备只有一个在运行,那么可以简单地说系统整体效率只有 50%。当使用多线程的时候,一个线程被 IO 阻塞,其他线程还可以继续使用 CPU。从而提高了 Java 进程利用系统资源的整体效率。 - 多核时代
多核时代,多线程主要是为了提高进程利用多核CPU的能力。
举个例子:假如我们要计算一个复杂的任务,我们只用一个线程的话,不论系统有几个 CPU 核心,都只会有一个 CPU 核心被利用到。
而创建多个线程,这些线程可以被映射到底层多个 CPU 上执行,在任务中的多个线程没有资源竞争的情况下,任务执行的效率会有显著性的提高,约等于(单核时执行时间/CPU 核心数)。
死锁
什么是死锁?
死锁 DeadLock,描述的是这样一种情况:多个进程/线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于进程/线程被无期限地阻塞,因此程序不可能正常终止。
产生死锁的4个必要条件
- 互斥
资源必须处于非共享模式,即一次只能有一个进程可以使用。如果另一进程申请该资源,那么必须等待直到该资源被释放为止。 - 占有并等待
一个进程至少应该占有一个资源,并等待另一资源,而该资源被其他进程所占有。 - 非抢占、不可剥夺
资源不能被抢占。只能在持有资源的进程使用完后释放。 - 循环等待
有一组等待进程,P0等待的资源被P1占有,P1等待的资源被P2占有,……,Pn等待的资源被P0占有。
这四个条件是产生死锁的必要条件 ,也就是说只要系统发生死锁,这4个条件必然成立,而只要上述条件之一不满足,就不会发生死锁。