目录
一、什么是进程?
用户角度:进程就是正在运行中的程序
操作系统角度:进程就是操作系统对运行中程序的描述信息--->进程描述符(简称PCB)。
二、如何描述进程?
1. 了解进程:
进程:运行中的程序,当一个程序运行起来,程序从磁盘中被加载到内存里,CPU 要调度这个程序运行,操作系统为了更好的管理这个运行中的程序,因此使用 pcb 描述符 进行描述,并管理这个运行中的程序,因此站在操作系统的角度,进程就是 pcb。在 Linux 下 pcb 的具体对象是一个结构体:task_struct
2. 进程描述符---PCB:
- 在 Linux 中描述进程的结构体就是 task_struct,它是 pcb 的一种特殊结构
- task_struct Linux 内核的一种 数据结构 ,它会被装载到 RAM (内存) 里,并且它还包含着进程的信息
3. task_struct 中包含的进程信息:
- 身份标识符 (进程 id,pid) :描述进程的唯一标识符,用于区别其他进程。
- 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。它的作用是找到进程对应的代码和代码依赖的数据的位置。
- 辅助进程调度的信息:
a) 优先级:相对于其他进程的优先级,它决定了进程被调度到 CPU 上执行的先后顺序。
b) 上下文( CPU 中的各种存储器):保存了该进程上次在 CPU 内部执行的“现场”,即进程执行时处理器的寄存器中的数据
c) 记账信息:统计了一个进程何时应该让出 CPU,也就是说它决定着进程什么时间需要占用 CPU,什么时间需要放弃 CPU,可能包括处理器时间总和,使用的时钟总数,时间限制,记账号等。
d) 进程的状态:记录的当前进程所处的状态。
4. IO 状态信息(文件描述符表):包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。
5. 信号相关信息
4. Linux 如何组织进程?
通过双向链表的形式对进程进行组织。所有运行在系统中的进程都以 task_struct 链表的形式存在内核里。
5. 查看进程
(1) 通过 ps 命令查看进程:
ps aux // 查看操作系统上的所有进程
ps aux | grep 进程名 // 查看指定进程
ps -ef // 查看系统的所有进程,但是没有 ps aux 显示的信息全面
ps -ef | wc -l // 统计系统中正在运行的进程个数
ps -ef | grep 进程名 // 查看指定进程
(2) 通过系统调用获取进程 id
- 父进程 id (PID)
- 子进程 id (PPID)
#include<stdio.h> #include<unistd.h> int main() { printf("pid:%d\n", getpid()); printf("ppid:%d\n", getppid()); return 0; }
6. 创建进程
(1)创建一个进程就相当于创建一个 pcb
(2)操作系统启动创建的第一个进程是 init 进程,后续操作系统上所有的进程都是由 init 进程直接或间接的创建出来的。用大白话讲:init 可以理解为其他进程的 “ 老祖宗 ”,并且 init 进程的进程id pid = 1
(3)通过系统调用创建进程---fork
- fork 是通过复制调用进程来创建子进程的。其中 复制 的是父进程的 pcb,因此代码共享,数据独有。
- 父进程创建子进程的过程:以父进程为模板,把父进程的 pcb 复制过来,然后稍加修改 ( pid / ppid ),内存指针基本相同,上下文(EIP)也是相同的,父子进程执行同一份代码,由于 EIP 也是相同的,所以 fork 执行完毕之后,父进程和子进程都要从 fork 之后的位置继续执行,直到程序结束。
- fork 返回值的含义: 1. 父进程返回的是子进程的 pid; 2. 子进程返回的是 0; 3. fork 执行失败返回 -1;
- fork 执行失败的原因 1. 内存不够--->执行 fork 时需要的内存和当前的 process 所使用的内存要一样大,如果当前 process 使用了很大的内存的 话,在 fork 时,可能会超出系统的内存大小,从而导致 fork 失败。 2. 子进程太多--->每个系统允许运行的进程的数量是有限的,当进程数已经达到了系统规定的上限时,errno 的值就会被设 置为 EAGAIN。这也就意味着创建进程失败。
- fork 之后,父进程先执行还是子进程先执行是不确定的,父子进程谁先执行取决于系统调度器的具体实现。
接下来就让我们用一段代码来更好的认识一下 fork
1 /* 通过系统调用,获取到当前系统的进程 id (pid) */ 2 3 // unistd.h 系统编程领域最重要的头文件,没有之一 4 // 里面包含了大部分的系统调用的 API 函数声明 5 #include<unistd.h> 6 #include<sys/types.h> 7 #include<stdio.h> 8 9 int main()