本文将介绍一系列与Linux系统编程有关的概念。
操作系统的核心——内核
操作系统 System 、内核 kernel
-
广义指完整的软件包,这包括用来管理计算机资源的核心层软件,以及附带的所有标准软件工具,诸如命令行解释器、图形用户界面、文件操作工具和文本编辑器等。
-
狭义指管理和分配计算机资源(即CPU、RAM和设备)的核心层软件。
术语“内核“通常是第二种含义,"操作系统”一般也是这层意思。
内核为管理计算机的有限资源所提供了软件层。
内核的职责
- 进程调度:每个进程都能获得对CPU的使用权。但是哪些进程能获得对CPU的使用,使用多长时间,这些都由内核进程调度程序(而非进程本身)决定。
- 内存管理:物理内存(RAM)属于有限资源,内核必须公平、高效地方式在进程间共享这一资源。
- 文件系统:内核在磁盘之上提供有文件系统,允许对文件执行创建、获取、更新以及删除等操作。
- 创建和终止进程:内核可将新程序载入内存(创建进程),为其提供运行所需的资源(比如CPU、内存以及对文件的访问等)。这样一个运行中的程序我们称之为“进程”。一旦进程执行完毕,内核还要确保释放其占用资源(终止进程),以供后续程序重新使用。
- 对设备的访问:计算机外接设备(鼠标、键盘、磁盘和磁带驱动器等)可实现计算机与外部世界的通信,这一通信机制包括输入、输出或是两者兼而有之。内核既为程序访问设备提供了简化版的标准接口,同时还要仲裁多个进程对每一个设备的访问。
- 联网:内核以用户进程的名义收发网络消息(数据包)。该任务包括将网络数据包路由至目标系统。
- 提供系统调用应用编程接口(API):进程可利用内核入口点(也称为系统调用)请求内核去执行各种任务。
- 多用户使用:每个用户都可以登陆进行系统,独立操作,而与其他用户大致无干。内核负责解决(多进程)访问硬件资源时可能引发的冲突,而用户和进程不需要关心。
内核态和用户态
现代处理器架构一般允许CPU至少在两种不同状态下运行,即:用户态和核心态(有时也称之为监管态)
-
用户态 User mode
CPU只能访问被标记为用户空间的内存,试图访问属于内核空间的内存会引发硬件异常。
-
内核态 kernel mode
当运行于核心态时,CPU既能访问用户空间内存,也能访问内核空间内存。
只有当处理器在核心态运行时,才能执行某些特定操作,比如宕机(halt)指令去关闭系统,访问内存管理硬件,以及设备I/O操作的初始化等。这确保了用户进程既不能访问内核指令和数据结构,也无法执行不利于系统运行的操作。
以进程及内核视角检视系统
在完成诸多日常编程任务时,程序员们习惯于以面向进程(process-oriented)的思维方式来考虑编程问题。然而为了更高视角看问题,有必要转换视角,站在内核的角度上来看问题。
对进程来说,许多事件的发生都无法预期。
- 进程不清楚自己在RAM中的位置。或者换种更通用的说法,进程内存空间的某块特定部分如今到底是驻留在内存中还是被保存在交换空间里,进程本身并不知晓。
- 与之类似,进程也闹不清自己所访问的文件“居于“磁盘驱动器的何处,只是通过名称来引用文件而已。
- 进程的运作方式堪称“与世隔绝“,进程本身无法创建出新进程,哪怕“自行了断”都不行。
- 最后还有一点,进程也不能与计算机外接的输入输出设备直接通信。
内核则是运行系统的中枢所在,对于系统的一切无所不知、无所不能,为系统上所有进程的运行提供便利。
-
由哪个进程来接掌对CPU的使用,何时“接任“,“任期“多久,都由内核说了算。
-
在内核维护的数据结构中,包含了与所有正在运行的进程有关的信息。随着进程的创建、状态发生变化或者终结,内核会及时更新这些数据结构。
-
内核所维护的底层数据结构可将程序使用的文件名转换为磁盘的物理位置。
-
此外,每个进程的虚拟内存与计算机物理内存及磁盘交换区之间的映射关系,也在内核维护的数据结构之列。
-
进程间的所有通信都要通过内核提供的通信机制来完成。
-
响应进程发出的请求,内核会创建新的进程,终结现有进程。
-
最后,由内核(特别是设备驱动程序)来执行与输入/输出设备之间的所有直接通信,按需与用户进程交互信息。
shell
shell是一种具有特殊用途的程序,主要用于读取用户输入的命令,并执行相应的程序以响应命令。有时,人们也称之为命令解释器。
术语登录shell(login shell)是指用户刚登录系统时,由系统创建,用以运行shell的进程。对UNIX系统而言,shell只是一个用户进程。
纵观UNIX历史,出现过以下几种重要的shell。
- Bourne shell:这款由Steve Bourne 编写的shell历史最为悠久,且应用广泛,曾是第七版UNIX的标配shell。Bourne shell包含了在其他shell中常见的许多特性:I/O重定向、管道、文件名生成(通配符)、变量、环境变量处理、命令替换、后台命令执行以及函数。对于所有第七版UNIX之后的系统而言,除了可能提供有其他shell之外,都附带了Bourne shell。
- C shell (csh):由Bill Joy于加州大学伯克利分校编写而成。其命名则源于该脚本语言的流控制语法与C语言有着许多相似之处。C shell当时提供了若干极为实用的交互式特性,并不为Bourne shell所支持,这其中包括命令的历史记录、命令行编辑功能、任务控制和别名等。C shell与Bourne shell并不兼容。尽管C shell曾是BSD系统标配的交互式shell,但一般情况下,人们还是喜欢针对Bourne shell编写shell脚本,以便其能够在所有UNIX实现上移植。
- Korn shell (ksh) : AT&T贝尔实验室的David Korn编写了这款shell, 作为Bourne shell的“继任者”。在保持与Bourne shell兼容的同时,Korn shell还吸收了那些与Cshell 相类似的交互式特性。
- Bourne again shell (bash):这款shell是GNU项目对Bourne shell的重新实现。Bash提供了与Cshell和Korn shell 所类似的交互式特性。Brian Fox和ChetRamey是bash的主要作者。bash或许是Linux上应用最为广泛的shell了。在Linux上,Bourne shell (bash)其实正是由bash仿真提供的。
- Z shell(Zsh):是一款可用作交互式登录的shell及脚本编写的命令解释器。Zsh对Bourne shell做出了大量改进,同时加入了Bash、ksh及tcsh的某些功能。自2019年起,macOS的預設Shell已從Bash改為Zsh。