本节重点:
*进程创建:
子进程复制父进程它复制的是什么
在复制的时候有一个技术叫做写时拷贝技术
fork的两个不同返回值
*进程的终止
*进程等待
*程序替换
一、进程创建
1.子进程在复制父进程的时候复制的是什么
它复制的是父进程的pcb,就是描述这个进程的一个结构体,这个结构体里面含有各种信息(进程id不会复制因为每个进程的进程是不同的,但是其他的内存指针、辅助信息都会复制),所以它复制以后子进程和父进程执行的任务差不多是相同的。
2.复制时的技术——写时拷贝技术
这个技术就是:我们本来在子进程复制了父进程的时候他们是“代码共享,数据独有”的,本来复制过来以后这个子进程指向的是和父进程是同一个虚拟地址空间,因此从表面上来看,他们的代码段和数据段看起来是一样的;但是我们知道每一个进程都应该是独立的,所以我们的子进程也需要开辟空间属于自己的物理空间。只是在刚开始的时候子进程可能根本不会用到数据,所以这个时候就不会开辟物理空间,这样不会浪费空间,等到他们其中有任意一个进程(子进程或者是父进程)需要改变数据的时候,这个时候子进程就会重新在内存上开辟属于自己的物理空间,这个时候子进程的虚拟地址空间也会发生改变,他们指向的不再是同一个虚拟地址空间了。这样的技术就叫做写时拷贝技术。
3.fork()函数的不同返回值
(1)fork()返回-1的时候:表示创建进程失败
(2)fork()返回0的时候:表示子进程的返回值
(3)fork()返回大于0的数:表示父进程的返回值,这个返回值是子进程的进程id
为什么是这样的情况:举个例子,我们在生活中,父母可以有多个孩子,我们的孩子只有一个父母,所以孩子可以不知道父母叫什么,但是我们的父母必须知道到底是那个孩子,这是相同的道理。
二、进程的终止
1.进程退出的原因
进程退出的原因是为了让父进程能够获取到子进程的退出原因,进而了解子进程退出运行的任务是否正确完成。
2.进程退出的场景
一共有三种退出场景:
(1)运行正常退出,结果正确
(2)运行正常退出,结构不符合预期
(3)异常退出
3.进程的退出方式
(1)main函数中的return
(2)exit
exit退出一个进程退出时刷新缓冲区+很多其他释放操作
(3)_exit
_exit退出时不会刷新缓冲区+直接释放掉所有的资源
三、进程等待
四、程序替换
首先我们来看一个进程运行哪个代码取决于我们的进程的虚拟地址对应哪段物理地址,这就意味着我们如果将虚拟地址的代码段指向的物理地址换成其他的地址那么我们的进程运行的代码段就会改变。
1.程序替换是什么
程序替换就是将代码段映射的区域换成另外一个区域,并且重新初始化数据段。
2.为什么要进行程序替换
因为我们的子进程在创建的时候是复制的父进程的pcb(除了进程id),那么他们会执行相同的任务,但是这并不是我们希望的,所以我们希望通过程序替换的方式让子进程可以实现和父进程不同的功能。
3.怎么实现
操作系统提供了一套接口都能实现程序替换,称为exec函数族
//这是一个程序替换函数介绍的例子
//int execl(const char *path,const char *arg,...);
#include<stdiio.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
execl("/bin/ls","ls","l","-a",NULL);
printf("-------------------");
return 0;
}
对于上面的程序替换成功的话就不会打印“----------------------”;它打印的内容是替换后的第一个参数的路径下的文件的内容。