进程创建:创建pcb
fork – 通过复制调用进程创建一个新的进程:
复制(pcb – 代码共享,数据独有) – 程序计数器(运行位置也一样)
返回值:父进程返回子进程的PID,子进程返回0
写时复制技术: 创建子进程的流程
vfork – 创建子进程,用同一个虚拟地址空间,为了防止调用栈混乱,因此父进程调用vfork会阻塞,阻塞子进程退出或者子进程程序替换,开创自己的地址空间
不能使用return退出,它会释放所有的地址空间,父进程崩溃
应该使用exit退出,因为它不会都释放掉
fork/vfork都是调用clone函数实现pcb创建并拷贝数据的;
vfork已经被淘汰了,fork通过写时拷贝技术代替了它
进程终止:进程退出
退出场景:
正常退出:结果符合预期和不符合预期
异常退出:常见的程序崩溃
如何退出:
main函数中的return 退出前刷新缓冲区
main函数中的exit(int retval) 是一个库函数 退出前刷新缓冲区
_exit 系统调用接口 不会刷新缓冲区,缓冲区的数据被丢弃
atexit 告诉操作系统进程退出的时候执行一下function函数
库函数和系统调用接口是上下级的封装调用关系
进程等待:等待子进程状态改变–获取子进程退出返回值
为什么要等待子进程退出:通知父进程获取子进程退出返回值,允许释放资源,避免成为僵尸进程
若获取了返回值,僵尸进程就会释放
如何等待
wait(int* statu)(阻塞函数)
waitpid(int* statu, int opt)
wait/waitpid两个函数都是默认是阻塞函数
获取子进程退出返回值:if statu & 0x7f == 0 正常退出
statu中高16位没有使用,其中低16位中,高八位存储子进程退出返回值,低八位中的高1位存储 core dump 标志;低七位中存储异常退出信号值,若信号值为0,表示正常退出
程序替换:替换一个进程正在运行的程序
重新加载一个新的程序到物理内存中,用一段新程序覆盖之前的程序,利用页表
如何替换?
exec函数组
int main(){
printf("ganyu\n");
//使用path这个路径的程序,替换当前进程运行的程序
//让当前进程运行ls程序的功能
execl("/usr/bin/ls","ls","l",NULL);
}