进程创建
fork函数初识
fork函数的功能是在已经存在的进程中创建一个子进程
#include <unistd.h> pid_t fork(void);
返回值:创建失败返回-1;创建成功,子进程返回0,父进程返回子进程的进程id;可以进行简单的类比:父亲可以有多个孩子,但是孩子却只有一个父亲,所以进程创建之后需要将孩子的id给父亲,而子进程只需要getpid()就可以获取自己的id
进程调用fork函数后,操作系统会分配新的内存块和内核数据结构给子进程;将父进程部分数据结构内容拷贝到子进程中;将子进程添加到进程列表中
fork函数返回值
为什么fork函数会有两个返回值呢?而且为什么返回之后,给父进程赋值子进程的id,给子进程赋值为0呢?为什么同一个返回值可以让if else同时成立呢?
接下来,深入了解该函数
首先用户使用fork函数,操作系统开始调用函数完成相应的任务
当函数fork()准备return pid;时,核心代码已经执行完毕,子进程也已经创建完成,并且在操作系统的运行队列中,准备被调度;所以,在执行return pid;之前,父子进程已经分流,可分别执行return pid;语句;返回的本质就是写入,子进程或父进程谁先返回,谁先写入id中,由于写时拷贝,同一个id会有两个不同的内容,根据不同的内容和判断语句if else进行匹配
fork常规用法
父进程希望复制自己,使父子进程同时执行不同的代码段
父进程希望子进程执行另一个不同的程序
fork调用失败的原因
系统中有太多的进程
实际用户的进程数超过限制
进程终止
进程退出场景
代码运行完毕,结果正确
代码运行完毕,结果错误
代码异常运行终止
进程常见退出方法
先介绍退出码,到目前为止,所写的代码中在最后都会加上 return 0;为什么一定是数字0,而不是其他数字呢???
进程退出时,会返回对应的退出码,标识进程执行的结果是否中正确;一般而言退出码都必须有对应的文字描述
退出码:0表示程序正常运行;!0具体的数字表示不同的错误
程序正常终止
可以通过 echo $查看最近一次的进程退出码
return 返回
调用exit
程序并没有立刻打印 hello world,而是两秒之后再打印的;而且退出码也与程序中exit(1)所设置的一致
调用_exit
程序压根就没有打印hello world,退出码仍是一致的
原因如下:
exit终止进程,主动刷新缓冲区
_eixt终止进程,不会刷新缓冲区
两者区别:exit是库函数;_exit是系统调用
return函数
return是较为常见的退出进程的方式,执行return n等同于执行exit(n)
进程等待
进程等待必要性
如果子进程退出,父进程一直不能获取其状态,就会造成子进程变成僵尸状态,进而造成内存泄漏
如果进程变成僵尸状态,操作系统也无能为力
父进程创建子进程的目的便是为了完成任务,所以需要知道子进程运行是否完成,结果正确与否,是否正常退出
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
获取子进程status
进程等待的方法
wait/waitpid,都有一个 status参数,该参数是一个输出型参数,由操作系统填充
如果传递NULL,表示不关心子进程的退出状态信息(子进程阻塞)
操作系统会根据该参数,将子进程的退出信息反馈给父进程
status不能简单地作为整体来看待,位图如下:信号等于0表示正常退出,退出状态就是退出码(位图在后面的学习中再详细学习)
status&0x7F进程退出信息;status >>8)&0xFF获取进程退出状态
wait方法
#include<sys/types.h> #include<sys/wait.h> pid_t wait(int*status);
返回值:如果成功,返回被等待进程的id;如果失败,返回-1
参数:输出型参数,获取子进程退出状态,不关心可设置为NULL;
前十秒一直在子进程中运行,状态是S+;十秒到十五秒之间,子进程终止运行,处于僵尸进程Z+;十五秒后父进程通过wait将子进程资源回收
waitpid方法
#include<sys/types.h> #include<sys/wait.h> pid_t waitpid(pid_t pid,int*status,int options);
返回值:如果成功,返回子进程的id;如果设置了选项WNOHANG,但是waitpid并没有已退出的子进程可以收集,则返回0;如果失败,返回-1,此时errno会被设置成相应的值以指示错误
参数:
pid:子进程id
status:WIFEXITED:若正常终止子进程,则为真,查看进程是否正常退出;WEXITSTATUS:若WIFEXIT非零,则提取进程退出码,查看进程的退出码
options:
0默认为阻塞状态;WNOHANG(非阻塞):若pid指定的子进程没有结束,则waitpd函数返回0,不予等待;若进程正常结束,则返回该子进程的id
status获取子进程信息的过程:子进程退出后,将退出状态,终止信息保存至PCB中;父进程系统调用waitpid,通过status获取子进程的退出状态,终止信息
通过宏获取status
阻塞VS非阻塞
阻塞:当父进程等待获取子进程资源时,如果子进程还未退出,父进程就一直在等其退出;非阻塞:当父进程等待获取子进程资源时,如果子进程还未退出,父进程可以去执行其他其他程序,不需要一直等待子进程,采取轮询
pid_t waitpid(pid_t pid,int*status,int options);中, option值为0时代表阻塞状态; option为WNOHANG时代表非阻塞
阻塞状态上面已经展示过,接下来展示非阻塞获取子进程资源
waitpid返回值:等于零,调用成功,但是子进程并没有退出;大于零,调用成功并且子进程也退出;小于零,调用失败
- 如果子进程已经退出,调用wait/waitpid时,会立刻返回,并释放资源,获取子进程退出信息
- 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能会阻塞
- 如果不存在该子进程,则立刻出错返回