操作系统是一种计算机软件。在硬件之上,应用程序之下。主要功能就是管理底下的计算机硬件,并为上层的应用程序提供统一的接口。
操作系统为了管理内存。将内存分为内核空间(内核态)和用户空间。内存空间和用户空间之间有隔离。
内核空间可以执行CPU的一些特权指令。用户空间则不能,这样是为了防止应用程序破坏硬件。
操作系统的资源是有限的,如果访问资源的操作过多,必然会消耗过多的资源,而且如果不对这些操作加以区分,很可能造成资源访问的冲突。
为了减少有限资源的访问和使用冲突,Unix/Linux的设计哲学之一就是:对不同的操作赋予不同的执行等级,就是所谓特权的概念
Linux操作系统中主要采用了0和3两个特权级,分别对应的就是内核态和用户态。运行于用户态的进程可以执行的操作和访问的资源都会受到极大的限制,而运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制。很多程序开始时运行于用户态,但在执行的过程中,一些操作需要在内核权限下才能执行,这就涉及到一个从用户态切换到内核态的过程
进程
进程是操作系统的核心概念,一个程序运行一次的完整的流程,就是一个进程。举个例子,科学家给自己的女儿做生日蛋糕,那么需要有一个具体的步骤,类似菜谱,我们称为计算机的代码。计算机按照每个步骤来做,做蛋糕就是一个进程,如果此时他的女儿哭闹了,这时科学家需要照顾女儿,不得不停下手中的做蛋糕的这个进程,但是为了知道 下次做到哪,需要做个标记,我们成为上下文。然后去照顾女儿,这又是一个进程,由做蛋糕换成照顾女儿,我们称之为上下文切换。
基本的进程状态主要有3种:执行、阻塞和就绪
进程调度
进程调度算法通常有:
- 先来先服务(FIFO ) 队列
- 时间片轮转 就是操作为每个进程分配相同的时间,成为时间片,当时间片结束,应用程序不管是否完成,都得交出执行权。
- 短任务优先 :操作系统进行预估每个进程的运行的时间,然后先调度时间短的任务
- 优先级调度:每个进程赋予一个优先级,每次需要进程切换时,找一个优先级最高的进程进行调度 类似数据结构的堆。
进程通信
进程之间通信,常用如下几种方式
- 管道
一个进程向存储空间的一端写入信息,另一个进程存储空间的另外一端读取信息,这个就是管道。就像两个人对白的媒介是空气也可以是线缆一样,管道所占的空间既可以是内存也可以是磁盘
- socket套接字
套接字(Socket)的功能非常强大,可以支持不同层面、不同应用、跨网络的通信。使用套接字进行通信需要双方均创建一个套接字,其中一方作为服务器方,另外一方作为客户方
- 信号量
类似我们生活中的红绿灯
在计算机中,信号量实际上就是一个简单整数。一个进程在信号变为0或1的情况下推进,并将信号变为1或0来防止别的进程同时推进。当该进程完成任务后,则将信号再改为0或1,从而允许其他进程执行。
- 共享内存
两个进程共同拥有同一片内存。对于这片内存中的任何内容,二者均可以访问。要使用共享内存进行通信,进程A首先需要创建一片内存空间作为通信用,而其他进程B则将片内存映射到自己的(虚拟)地址空间。这样,进程A读写自己地址空间中对应共享内存的区域时,就是在和进程B进行通信
- 消息队列
消息队列是一列具有头和尾的消息排列,新来的消息放在队列尾部,而读取消息则从队列头部开始
内存
内存是程序运行的载体,所有的进程都在进程中,操作系统就是为了更高效、更安全的管理内存。
虚拟内存:vm 我们的程序都跑在内存中,但是有时候我们的内存不足以运行所有的程序。所有就有了虚拟内存,虚拟内存本质上磁盘空间。操作系统将一些内存中暂时没有运行的程序放到磁盘中。等到运行时,再加载回内存。
内存管理
- 分页
将虚拟内存空间和物理内存空间皆划分为大小相同的页面,如4KB、8KB或16KB等,并以页面作为内存空间的最小分配单位,一个程序的一个页面可以存放在任意一个物理页面里。类似我们书本中的页
- 分段
分段管理就是将一个程序按照逻辑单元分成多个程序段,每一个段使用自己单独的虚拟地址空间
分段就是类似我们的文章中的段落。内容的大写不固定。
系统调用和函数调用
操作系统是一个系统程序,即为别的程序提供服务的程序。
系统调用:应用程序直接调用操作系统的接口,我们成为系统调用
函数调用: 通过库函数调用操作系统的接口,本质上库函数再发起系统调用。
函数库调用 | 系统调用 |
---|---|
平台移植性好 | 依赖于内核,不保证移植性 |
调用函数库中的一段程序(或函数) | 调用系统内核的服务 |
一个普通功能函数的调用 | 是操作系统的一个入口点 |
在用户空间执行 | 在内核空间执行 |
它的运行时间属于“用户时间” | 它的运行时间属于“系统”时间 |
属于过程调用,调用开销较小 | 在用户空间和内核上下文环境间切换,开销较大 |
库函数数量较多 | UNIX中大约有90个系统调用,较少 |
典型的C函数库调用:printf scanf malloc | 典型的系统调用:fork open write |