进程1111
一、操作系统的“管理”——简要概述
核心思想:
操作系统可以被比作“硬件的管理者”和“资源的组织者”。它的主要工作就是“管理硬件”和“组织资源”。
比喻:
想象你家里有一堆杂乱的物品(硬件,比如CPU、内存、硬盘、鼠标、键盘等),每个物品都有自己的属性(存储器容量、连接状态等)。操作系统就像一个管理员,把这些物品用“结构体struct”描述,把它们组织成不同的数据结构,比如链表、树等。
例如:
- 将硬件描述为一个“硬件结构体”,里面包括硬件的类型、状态、连接的接口等属性。
- 这些硬件用链表(比如所有硬盘连接在一条链表里)管理,方便“增删查改”。
总结:
操作系统的“管理”可以理解为:描述硬件,把它们组织成“结构体结构”,然后通过不同的数据结构(链表、数组、树)管理硬件的状态和资源。
二、什么是“进程”?
定义:
进程就是“运行中的程序”,当然也可以理解为:
- 当你在计算机上运行一段软件或命令,系统会把这个“事件”定义为一个“进程”;
- 每个进程都有一个唯一的“编号”——PID(Process ID),就像身份证一样。
关键点:
- 进程是系统中“正在运行的程序实例”。
- 你启动一个程序,例如打开浏览器,那么它就变成一个“活动的进程”。
理解:
比如:你用浏览器打网页,浏览器这个应用程序被操作系统转换为一个“正在运行的实体”,它就被叫做“进程”。
三、描述进程——PCB(进程控制块)
PCB的作用:
每个进程在系统中,都由一个叫做“进程控制块(Process Control Block,简称PCB)”的结构体存放信息。
在Linux系统中,这个结构体叫task_struct
。
内容分类:
PCB就像“进程的身份证和档案袋”,里面存放了各种各样的“信息”:
内容类别 | 说明 |
---|---|
标识符 | 唯一标识这个进程的编号(PID) |
状态 | 这个进程的当前状态(正在运行、睡眠、停止等) |
优先级 | 进程的优先级,决定调度先后,数字越低越优先 |
程序计数器 | 下一要执行的指令地址,也叫PC(Program Counter) |
内存指针 | 指向代码段、数据段、共享内存的地址 |
寄存器保存区 | 保存CPU中的寄存器信息,暂停和恢复时用 |
I/O状态 | 输入输出请求和使用的设备信息 |
统计信息 | 处理器时间、运行时间、限制时间等 |
简单总结:
PCB是“存放进程信息的容器”,包含了进程的大战略信息(状态、优先级、资源等)。
四、如何查看和管理进程
1. 查看所有进程
-
通过
/proc
文件系统:你可以访问
/proc/1
来获取编号为1的进程信息(在Linux里,/proc/
是“虚拟文件系统”存放所有关于进程、硬件信息的接口) -
使用 Linux 命令:
ps
:显示当前系统的进程信息top
:实时动态显示进程信息
ps -ajx
这条命令会列出所有进程信息(用户、PID、优先级、状态等)
2. 杀死某个进程
- 命令:
kill -9 pid
- 这里
-9
代表“强制终止”,pid
是目标进程编号。
3. 查看进程的详细信息
- 通过调用系统函数
getpid()
获取自己的PID - 通过
getppid()
获取父进程PID
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {printf("我的PID:%d\n", getpid());printf("父PID:%d\n", getppid());return 0;
}
4. 创建新进程
- 使用
fork()
函数 - 运行流程:
- 调用
fork()
后,系统会复制父进程,生成一个“子进程” fork()
的返回值:在父进程返回子进程的PID,在子进程返回0
- 调用
示例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {int ret = fork();if (ret < 0) {perror("fork失败");return 1;} else if (ret == 0) {printf("我是子进程,PID:%d\n", getpid()); //子进程} else {printf("我是父进程,子进程PID:%d\n", ret);}sleep(1);return 0;
}
五、进程的特性和状态
特性:
- 竞争性: 多个进程争夺CPU资源,谁先得到资源由调度策略决定。
- 独立性: 每个进程拥有自己的资源,不会互相干扰。
- 并行: 多核CPU可以让多个进程同时运行。
- 并发: 单核CPU上通过时间片轮转实现多进程“共存”。
状态分类:
状态 | 说明 | 示例命令或示意 |
---|---|---|
运行(R) | 进程正在执行或在就绪队列等待调度 | ps 命令可以看到。 |
睡眠(S) | 等待事件或资源(睡眠状态) | 使用kill -19 pid 暂停进程 |
磁盘休眠(D) | 等待IO,不可中断 | 出现磁盘I/O等待,不能用普通信号唤醒 |
停止(T) | 被暂停、停止状态 | 使用 kill -STOP pid |
-
僵尸进程(Z):表示进程已结束,但父进程没有读取退出信息,仍占用系统资源。
-
孤儿进程:父进程先退出,子进程会被
init
(PID=1)“收养”。
六、进程调度与优先级
- 调度:CPU按照一定的策略,把运行时间分配给不同的进程
- 优先级(PRI):数字越小,优先级越高。
- Nice值(NI):用来调整优先级,范围[-20, 19],负值代表“更优先”,正值代表“较低优先级”。
优先级计算:优先级 = PRI + NI
比如:
- 如果一个进程的PRI为60,NI为-10,那么它的优先级就是50(相对更高的优先级)。
- 通过
top
,可以用r
更改nice值。
七、地址空间和虚拟地址
- 每个进程都有“虚拟地址空间”,就像一个虚拟化的内存关卡
- 这些虚拟地址通过“页表”映射到实际的物理内存中
好处:
- 让每个进程“看似”拥有连续的内存空间
- 内存管理变得灵活(如写时复制)
写实拷贝:
- 父子进程共享相同的内存区域(复制前的共享)
- 如果任何一方改动,系统会“复制”一份,避免相互干扰
八、调度队列(Linux 内核中的管理)
-
Requeue队列:
每个CPU有一个“运行队列”,存放“待调度进程”
-
按优先级排序,优先级高的先调度(数组
queue[140]
) -
活动队列(active):存放待运行的进程
-
过期队列(expired):存放本轮时间片耗尽、等待下轮的进程
调度策略:
- 系统会在两个队列间切换(队列交换:active 和 expired)
- 通过“bitmap”比特位标记哪些优先级队列非空,加快查找速度