1.进程创建:
fork()
1.以父进程为模板复制创建出一个子进程,父子进程代码共享,数据独有(写时拷贝)
2.fork的返回值,父进程返回值为子进程的PID,子进程返回0
3.取决于CPU的调度
vfork()也是创建一个子程序:
1.子进程没有(退出)或者运行其他程序则父进程是阻塞的,也就是以为这子进程是先运行的
父进程退出(不能再main函数中return中)之后
子进程才能退出
2.子进程先运行的原因:
因为创建出子进程,大多时候都是为了让它运行其他程序
3.父进程阻塞的原因:
vfork创建子进程后,父子进程是共用一块虚拟地址空间,那么他们共用同一个栈区,有可能会造成调用栈混乱
vfork设计出来的目的就是为了创建一个子进程,然后直接运行其他的程序。重新运行其他的程序就是重新给子程序开辟新的空间,
更新它自己的一份地址空间和页表
自从fork函数使用了写时拷贝技术之后,这个函数就淘汰了
2.进程终止:
终止方式:
1.main函数中得return
2.exit(int status)库函数调用
在程序任意位置调用都会使进程退出
status是进程的退出状态
3._exit(int status)系统调用接口
在程序任意位置调用都会使进程退出
exit最终调用的就是这个借口退出的
exit与_exit的区别
exit是温和性的退出,在退出前会温和的释放资源,刷新缓冲区
_exit是暴力退出,直接释放资源,不会刷新缓冲区。
不管哪种主动退出方式,都会返回一个数字,这个数字是进程的退出状态,它表明了进程的退出原因
1.正常运行完毕,结果符合预期
2.正常运行完毕,结果不符合预期
3.异常退出,返回状态将不能作为评判标准
3.进程等待:
一个进程退出之后因为要保存自己的退出原因,因此并不会释放所有的资源,它等着父进程查看它的退出原因,然后释放所有资源。
假如父进程根本就没管,那么这个子进程就成了将是进程,危害就是造成资源泄漏
因此为了防止出现僵尸进程,父进程就应该管一下子进程的退出。
进程等待就是等待子进程的状态改变,获取子进程的退出状态码,允许系统释放子进程的所有资源,这时候子进程在所有资源才会被释放掉
进程等待是避免产生僵尸进程的主要方式
进程等待的方式:
1.pid_t wait(int *status)
status 用于获取子进程退出状态码
返回值是返回退出的子进程pid,如果没有子进程程序报错返回。
wait 函数目的就是为了等待任意一个子进程的退出
因为wait是一个阻塞型的函数,因此如果没有子进程退出
那么他就是一直等待,直到有子进程退出。
2.pid_t waitpid(pid_t pid,int *status,int options);
pid: -1:等待任意子进程
>0:等待指定的子进程
status:获取退出状态码
options:
0:阻塞 WNOHANG:非阻塞
返回值: -1:出错
==0 : 没有子进程退出
>0 : 退出子进程的pid
两种接口获取状态----
实际使用了两个字节:
高八位:正常退出的状态码 第八位:最高一位coredump标志,异常退出的信号值。
4.进程程序替换:
程序替换替换的是代码段所指向的物理内存区域,相当于让虚拟地址空间中得代码段的地址指向了物理内存的另一端代码位置。
这样的话虚拟地址空间中原先的数据区域以及堆栈都会重新初始化,因为现在的代码运行的根本不是复制的那些数据
但是这个进程的PCB还是原来的PCB。
一个main程序有三个参数,参数个数,参数的字符串指针,环境变量
exec函数族:
execl execlp execle
execv execvp execve
l和v的区别: l是参数平铺一个一个通过exec函数参数赋予,v参数直接使用字符串指针数组
execl和execv 需要我们给出要替换的程序的全路径名
execlp和execvp 只需要给出要替换的程序全名称就行
execle和execve 重新自己组织环境变量,不使用现有的