进程创建
fork()函数
使用fork系统调用通过复制调用进程来创建一个新进程,调用fork的进程我们称为父进程,创建出来的新进程称之为子进程。
pid_t fork(void);
fork的返回值
对于父进程来说,返回值是子进程的进程pid。
对于子进程来说,返回值是0。
父子进程创建后,子进程复制了父进程的PCB中的大部分数据,因为父子进程是以父进程为模板来创建的,因此父子进程的代码段是完全一样的,也就是说,子进程运行与父进程相同的程序,直到用户做出判断后,父进程进行父进程的操作,子进程进行子进程的操作,相对独立,操作结束后若均未退出的话则运行剩下相同的程序。
vfork函数
创建一个子进程(fock使用写时拷贝技术后,vfock就被淘汰了)
pid_t vfork(void);
vfork函数的特性
- 子进程没有(退出)或者运行其他程序,父进程是阻塞的(因为vfork创建子进程后,父子进程是共用一块虚拟地址空间,那么他们共用一个栈区,有可能回造成调用栈混乱),也就意味着子进程是优先运行的(因为创建出子进程大多时候都是为了让他运行其他程序),子进程退出(不能在main函数中return)之后,父进程才能运行
- vfork设计出来的目的就是为了创建一个子进程,然后直接运行其他的程序。重新运行其他的程序就是重新给子进程开辟新的空间,更新他自己的一份虚拟地址空间和页表
- 子进程先运行,等到子进程exit退出或者程序替换之后,父进程才开始运行,子进程如果使用return退出,会造成调用栈混乱,导致父进程陷入死循环(centOS环境)
进程终止
终止方式
- main函数中return退出
- exit 库函数
- _exit 系统调用接口
exit与_exit的区别
exit是温和性的退出,在退出前会温和的释放资源,刷新缓冲区
_exit是暴力退出,直接释放资源退出,不会刷新缓冲区
杀死进程
kill
- kill-l 查看信号
- kill pid
- kill -9 强制杀死进程
- kill -进程组id 杀死一组进程
进程等待
wait函数
pid_t wait(int *status)
//函数功能
//阻塞等待子进程退出,回收子进程残留资源 ,获取子进程结束状态(退出原因)。
//头文件
#include<sys/tyoes.h>
#include<sys/whit>
//参数
status 输出型参数,获取子进程退出状态(退出状态码),可设置成为NULL(不关心退出状态)
返回值
成功返回子进程的pid
失败返回-1
waitpid函数
pid_t waitpid(pid_t pid, int *status, int options)
//waitpid是一个阻塞/非阻塞可选的函数
//参数
pid
-1 //等待任意一个子进程
>0 //等待指定子进程
status //获取退出状态码
options
0 //阻塞
WNOHANG //非阻塞
返回值
-1 //出错
0 //没有子进程退出(设置成非阻塞的情况下)
>0 //退出的子进程pid
子进程的退出状态码
//退出状态码的一些操作
WIFEXITED(status) //判断是否正常退出
WEXITSTATUS(status) //获取status中的子进程退出码
进程替换
替换原理
创建子进程后,子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程(调用main函数的函数)开始执行(替换的是程序所运行的代码,将另一端程序加载到内存中,通过页表将原先的进程的映射关系,重新建立在新程序在内存给中的地址,相当于替换了进程所运行的程序以及所要处理的数据,因此,可以这样认为,替换了代码段,重新初始化数据段)。
exec函数族
//exec函数族中的函数只有在失败时才会返回-1
//即程序在调用成功时会直接执行调用程序结束,只有在调用失败时才会返回继续执行原程序
//函数族功能:替换当前的程序
//01
int execl(const char *path, const char *arg, ...);
//path 源程序(替换的文件)的文件路径名
//arg 参数,通常为可执行程序名
//NULL 结束标志
//02、
int execl("/bin/ls", "ls", "-l", NULL); //不定参数列表需要NULL结尾
//03、
int execlp(const char *file, const char *arg, ...);
//file 文件名称,必须再指定路径下,若没有,则需要自己添加路径
int execlp("ls", "ls", "-l", NULL);
//04、
int execle(const char *path, const char *arg, ..., char *const envp[]);
//envp //环境变量, 字符串指针数组
//需要引入环境变量表
char *env[] = {"MYVAL = 10", NULL}; //注意以NULL结尾
int execle("./test", "test", "-a", NULL, env);
//05、
int execv(const char *path, char const argv[]);
char *arg[] = {"ls", "-a", NULL};
int execl("/bin/ls", arg);
//06、
int execvp(const char *file, char const argv[]);
//07、
int execve(const char *path, char const argv[], char *const envp[]);