1,fork()函数:在已经存在的进程中创建一个子进程。
子进程返回0,父进程返回的是子进程的pid 。
Fork的常规用法:父进程复制自己,使得父子进程同时运行不同的代码,一个进程执行不同的程序
2,vfork()函数:
创建一个子进程,子进程没有运行其他程序或者退出之前,父进程阻塞在vfork处不执行
也是用来创建子进程,但是 vfork⽤于创建一个子进程,而子进程和⽗进程共享地址空间,fork的⼦进程具有独⽴立地址空间
vfork保证⼦进程先运⾏行,在它调用exec或(exit)之后⽗进程才可能被调度运行。
3,进程退出
通过 echo$? 查看退出码(0-255之间的数字)
exit 在进程的任意位置调用exit都会推出进程,退出的时候会逐步释放所有的资源,刷新缓冲区,做很多清理关闭等操作
_exit 强制推出进程,直接释放资源
return 只有在main中执行才会退出进程,在main中return和调用exit效果一样
4,进程等待
⼦进程退出,⽗进程如果不管不顾,就可能造成‘僵尸进程’的问题,进⽽造成内存泄漏。另外,进程⼀旦变成僵尸状态,就⼑枪不入,kill -9 也⽆能为⼒力,因为谁也没有办法杀死⼀个已经死去的进程。最后,⽗进程派给⼦进程的任务完成的如何,我们需要知道。如子进程运行完成,结果对还是不对,或者是否正常退出。父进程通过进程等待的⽅方式,回收子进程资源,获取子进程退出信息
Wait(int *statu)
功能:等待任意子进程的退出(阻塞式调用,如果没有子进程退出就一直等待,不返回,直到子进程退出)
Statu:用于获取子进程退出状态,如果不关心置空
Waitpid
可以设置为非阻塞,等待指定的子进程退出,也可以等待任意一个子进程退出
Pid_t waitpid(pid_t pid , int *status , int options);
Pid:
-1 等待任意子进程退出
>0 等进程id==pid 的子进程退出
statsus:用于获取子进程提出吗
options:选项参数
waitpid函数第一个参数给-1,第三个参数给0:阻塞任意一个子进程退出,效果相当于wait。
非阻塞WNOHANG:如果没有子进程退出,则立即报错返回,如果有则回收资源。
阻塞:为了完成一个功能发起一个函数调用,如果没有完成这个功能则一直挂起等待功能完成才返回。
非阻塞:为了完成一个功能发起一个函数调用,如果现在不具备完成的条件,则立即返回而不等待。
进程退出状态码获取:
在wait的参数中存储了子进程的退出原因以及退出码,而参数中只用了低16位两个字节用于存储这些信息,虽然使用了4个字节来获取子进程的退出码,但是实际上只用了两个字节(低16位)
在这低16位中,
高8位存储子进程的退出码,只有子进程运行完毕退出时才会有,低8位为0
低8位存储子进程引起异常退出时的信号值,只有子进程异常退出时才会有,高8位为0
(低7位储存导致子进程异常退出所接收到的信号,第8位储存code mod)
5,进程程序替换
创建一个子进程大多时候,并不希望子进程做跟父进程一样的事情,而是希望能够运行一段其他代码,这时候就需要程序替换,程序替换只替换了代码段,初始化了数据区域,因此程序替换并不会重新创建虚拟地址空间和页表,只是替换其中的内容。
替换后这个进程将从入口函数开始
替换方法:exec函数族
execl与execv的区别:
参数如何赋予(前者平铺,后者指针数组)
execl与execlp的区别:
execl需要告诉操作系统这个程序文件的全路径 /bin/ls
execlp不需要告诉路径,只需要告诉文件名即可,会自动到PATH中的路径下寻找
execl与execle的区别:
execl是继承于父进程的环境变量
execle是由用户来组织环境变量
execl函数需要我们明确告诉操作系统,这个要替换的程序在哪里
if(execl("/bin/ls","ls","-l",NULL)<0)
{
perror("execl error");
Return -1;
}
execlp函数只需要告诉操作系统这个要替换的程序名称即可
execlp(“ls”,“ls”,“-l”,NULL)
execle需要我们自己组织环境变量,以一个指针数组来存储
char *env[]={“MYENV=neihoua”}
main(int argc, char *argv[], char *env[])函数中可以有三个参数
argc:程序有几个命令行参数
argv:用于储存这些参数
env:用于储存环境变量