计算机中的抽象
计算机系统中的一个重大主题就是提供不同层次的抽象表示,来隐藏实际实现的复杂性。
在处理器里,指令集架构提供了对实际处理器硬件的抽象。使用这个抽象,机器代码程序表现得就好像运行在一个一次只执行一条指令的处理器上。底层的硬件远比抽象描述的要复杂精细,它并行
地执行多条指令,但又总是与那个简单有序的模型保持一致。
进程与线程
进程是操作系统最基础的抽象,它是对一个正在运行的程序的抽象,操作系统会提供一种假象好似应用程序独占了整个计算机,进程提供了两个最重要的功能,实现程序并发执行与资源隔离与保护
- 实现程序并发执行
通过进程可以允许多个程序“同时”运行,最大化硬件资源利用率,一个进程中包含: - 代码段:程序的指令(只读)
- 数据段:全局变量、静态变量。
- 堆:动态分配的内存(如
malloc
)。 - 栈:函数调用、局部变量。
- 进程控制块:存储进程状态(运行、就绪、阻塞)、寄存器状态、PID等元数据。
这些内存统称为一个进程的上下文,操作系统会通过时间片轮转或优先级调度,允许多个进程“同时”运行控制cpu。具体的实现是,当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文、恢复新进程的上下文,然后将控制权传递到新进程。新进程就会从它上次停止的地方开始运行。
- **资源隔离与保护
其核心思想是通过硬件和软件机制,确保不同用户、进程或任务在共享同一物理资源时,彼此独立、互不干扰,从而提升系统的安全性、稳定性和可靠性。
进程可以防止进程间相互干扰,确保系统稳定性与安全性,每个进程只能访问自身虚拟内存空间,无法直接读写其他进程数据(除非共享内存),当一个进程崩溃时不会导致整个系统或其他进程崩溃,
线程
线程是进程的基本单位,一个进程必定会有一个或一个以上的线程在运行,所有线程共享进程的资源(如内存、文件句柄),但每个线程拥有独立的执行上下文(如程序计数器、寄存器、栈)。线程的创建与使用消耗都要比进程更低
虚拟内存
虚拟内存是对主存的抽象,它让每个进程都以为自己独占的使用了整个主存,每个进程看到的内存都是一致的,通过虚拟内存可以防止进程直接访问其他进程或内核的内存,,下面是虚拟内存的结构图
- 程序代码和数据:对所有的进程来说,代码是从同一固定地址开始,,紧接着的是和C全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的
- 堆:代码和数据区后紧随着的是运行时堆。代码和数据区在进程一开始运行时就被指定了大小,与此不同的,当调用像malloc和free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。
- 共享库:大约在地址空间的中间部分,是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域。
- 栈。位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地,每次我们调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩。
- 内核虚拟内存。地址空间顶部的区域是为内核保留的。不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些操作。
文件
文件是对I/O设备的抽象,将磁盘、网络、设备等异构资源统一为字节流接口,实现持久化存储。程序可以通过文件描述符访问文件、管道、套接字等内容。
文件抽象解决的问题解决了多个问题:
- 设备统一性:磁盘、键盘、网络均可通过
read/write
操作(如Linux的“一切皆文件”) - 持久化存储:程序退出后数据仍保留(与进程内存的易失性相反)。
- 权限与共享:通过文件权限位(rwx)控制多用户访问。