一、进程与PCB
进程是什么?
粗略的说,进程就是运行中的程序。
那么PCB又是什么?
PCB也叫进程控制块。对程序运行的动态描述,就叫做PCB,在Linux下是一个task_struct结构体。
在PCB中存储了程序运行的各种信息,如果程序被中断,PCB就会记录程序此时的状态,如果程序再次运行,该从哪里开始,这些信息都会在PCB中记录。
PCB中的描述信息:
内存指针、上下文数据,程序计数器,进程ID(pid),IO信息,进程优先级、进程状态、记账信息等…
- 优先级:相对于其他进程的优先级。
- 程序计数器:程序中即将被执行的下一条指令的地址。
- 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
- 上下文数据:进程执行时处理器的寄存器中的数据
程序的运行过程:
程序运行都会被加载到内存中,要运行哪个程序,操作系统就找到对应程序的PCB,在PCB取出程序运行所需要的信息,加载到cpu上,cpu就开始运行这个程序。
总结:
对于操作系统来说,进程就是一个程序运行的描述,通过这个描述,操作系统可以进行程序的调度运行管理。实际上对于系统来说,进程就是pcb。
二、进程查看
命令:ps -ef
UID代表进程所属的用户,PID代表子进程,PPID代表父进程,CMD代表是通过哪个命令创建的进程
命令:ps -aux(进程信息更加详细)
%CPU代表进程所占CPU的百分比,%MEM代表进程所占内存的百分比,STAT代表进程的状态。
上面两个命令,查看的是全部进程,我们平时在使用时,通常会查看需要查看的进程,通常会使用管道符|
,例如,我们要查看名为fork
的进程,如果要查看它的父进程:ps -ef | grep fork
;如果要查看它的进程状态:ps -aux | grep fork
。
三、创建进程
1. 通过系统调用获取进程ID
头文件:#include <unistd.h>
PID(子进程):pid_t getpid(void);----->获取子进程PID
PPID(父进程):pid_t getppid(void);----->获取父进程PPID
2. 创建进程
进程就是一个pcb,在Linux中是一个task_struct结构体,创建进程实际就是创建了一个task_struct结构体。
创建进程的接口:pid_t fork(void)
,头文件:#include<unistd.h>
。通过复制调用这个接口的进程(父进程),创建一个新的子进程。
子进程的创建是通过复制父进程,那么为什么只有父进程打印了第一条语句?
是因为复制父进程的同时,也会将父进程pcb中的信息复制过去,比如上下文数据、程序计数器等。父进程执行下一条指令的位置也会复制给子进程,子进程也会从这个位置继续执行。例如上图,父进程下一句执行printf打印pid,复制给子进程,子进程也会从这个位置开始执行。当然,父进程的pid不会复制给子进程。 每个进程的pid都不同。
创建了子进程,哪个进程先运行不一定,取决与cpu调度。
fork返回值:
父子进程都会调用return语句,因此父子进程就各有各的返回值。父进程返回值为子进程的pid,子进程返回值为0。 因此,就可以通过不同的返回值对父子进程进行分流,让父子进程进入各自的判断,完成不同的功能。
上图代码,父子进程进行分流,分别实现自己进程的功能。
创建进程的规则:父子进程代码共享,数据各自开辟空间,私有一份
在父进程中修改了val值,但子进程的val值并没有被修改,就说明父子进程的val不是同一个val,父子进程都有各自的val值。