目录
[1 冯・诺依曼体系结构](#1 冯・诺依曼体系结构)
[2 操作系统 (OS) 定位](#2 操作系统 (OS) 定位)
[2.1 广义与狭义操作系统](#2.1 广义与狭义操作系统)
[2.2 OS 两大目标](#2.2 OS 两大目标)
[2.3 系统调用 & 库函数](#2.3 系统调用 & 库函数)
[3 进程基础概念 & PCB (task_struct)](#3 进程基础概念 & PCB (task_struct))
[3.1 什么是进程](#3.1 什么是进程)
[3.2 PCB task_struct(Linux 的进程控制块)](#3.2 PCB task_struct(Linux 的进程控制块))
[3.3 查看进程的两种方式](#3.3 查看进程的两种方式)
[3.4 获取 PID、PPID 系统调用](#3.4 获取 PID、PPID 系统调用)
[4 fork () 创建子进程](#4 fork () 创建子进程)
1 冯・诺依曼体系结构

现代计算机(PC、服务器)均遵循冯诺依曼体系,五大部件:输入设备、存储器、CPU (运算器 + 控制器)、输出设备。
⚠关键点:这里的存储器指内存
- CPU只能直接读写内存,不能直接访问外设(键盘、显示器、硬盘);
- 外设和 CPU 之间的数据交互,必须经过内存中转;
- 所有设备数据交互都要和内存打交道。


拓展存储层次:寄存器 → L1/L2/L3 高速缓存 → 内存 DRAM → 本地磁盘 → 远程网络存储。速度逐级变慢,容量逐级变大。
思考题:QQ 聊天数据流向:键盘输入 → 内存 → CPU 处理 → 内存 → 网卡发送;接收消息:网卡收到数据到内存,CPU 处理,内存把数据输出到显示器。
2 操作系统 (OS) 定位
2.1 广义与狭义操作系统
- 狭义 OS:内核 Kernel,四大核心模块:进程管理、内存管理、文件管理、驱动管理。
- 广义 OS = 内核 + shell 外壳 + 标准库 + 系统工具软件。

2.2 OS 两大目标

- 向下:管理计算机全部软硬件资源;
- 向上:给上层应用程序提供安全、稳定的运行环境。
操作系统本质就是一款管理软件。 管理的实现思路两步:
- 描述 :用
struct结构体把被管理对象的全部属性描述出来; - 组织:用链表 / 红黑树等数据结构把这些结构体对象组织起来。
类比学校管理学生:学生信息用结构体描述,用链表把全部学生信息组织起来。



2.3 系统调用 & 库函数

内核不允许用户程序直接访问,内核向外暴露接口叫做系统调用。 系统调用接口功能底层,使用门槛高;标准库(libc)会对系统调用做封装,形成库函数。
用户程序 → 库函数 → 系统调用 → 内核 → 硬件。
3 进程基础概念 & PCB (task_struct)
3.1 什么是进程
- 课本概念:程序的一次执行实例,正在运行的程序。
- 内核视角:进程是分配系统资源(CPU 时间、内存)的基本实体。
- 真实理解:
进程 = 内核数据结构PCB(task_struct) + 磁盘加载进来的程序代码和数据
程序:磁盘上静态的可执行文件;进程:内存中正在运行的实例,一个程序可以生成多个进程。
3.2 PCB task_struct(Linux 的进程控制块)

Linux 内核中,每一个进程对应一个task_struct结构体,存放在内存中,保存进程全部属性。
task_struct 核心成员:
- 标识符:PID 进程 ID,PPID 父进程 ID,用来唯一标识进程;
- 进程状态:运行、睡眠、僵尸等状态,退出码、退出信号;
- 优先级:决定 CPU 调度先后;
- 程序计数器:下一条要执行指令的地址;
- 内存指针 :指向该进程虚拟地址空间
mm_struct; - 上下文数据:CPU 寄存器的值;进程被切走的时候保存寄存器,恢复运行时回填;
- I/O 信息:进程打开的文件列表;
- 记账信息:CPU 使用时长统计。
内核把所有进程的
task_struct用双向链表组织管理。
3.3 查看进程的两种方式
-
/proc伪文件系统:内核把进程信息导出成目录,/proc/PID查看指定进程; -
用户命令:
ps aux #查看系统全部进程
ps axj
top #动态监控进程资源
3.4 获取 PID、PPID 系统调用
头文件 <sys/types.h> <unistd.h>
getpid(); // 获取自己进程PID
getppid(); // 获取父进程PID
4 fork () 创建子进程
pid_t fork(); 创建子进程。
- 调用一次,返回两次;
- 父进程返回子进程 PID ;子进程返回0 ;出错返回
-1; - 子进程以父进程为模板创建,代码共享,数据写时拷贝。
cpp
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t ret = fork();
if(ret < 0)
{
perror("fork");
return 1;
}
else if(ret == 0)
{
printf("子进程 pid:%d\n", getpid());
}
else
{
printf("父进程 pid:%d 子pid:%d\n",getpid(), ret);
}
sleep(1);
return 0;
}
重点疑问:为什么一个函数会有两个返回值? fork 内核做两件事:创建子进程 task_struct、拷贝页表;fork 在子进程准备完毕之后,父子两个进程都会从 fork 返回处继续执行,所以得到两个返回值。 一般配合
if‑else做父子进程业务分流。



