进程创建
创建子进程使用fork函数
fork有两个返回值
pid_t fork(void)
pid_t相当于int
失败:返回小于0的值
成功:
0,返回给子进程
大于0 ,返回子进程的pid给父进程
fork失败原因:内存不足,创建PCB是需要内存的(内核)
父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
获取当前进程的pid,使用getpid函数
获取当前进程的父进程的pid,使用getppid函数
pid_t vfork (void);
vfork :
- vfork创建出来的子进程PCB也是拷贝父进程PCB的,但是子进程的PCB执行父进程的虚拟地址空间
- 这带来了父、子进程调用栈混乱的问题。
- 因此vfork先让子进程执行,父进程等待子进程执行完毕之后再执行
进程终止:
让一个进程退出
场景:
- 代码运行完毕,结果正确
- 代码运行完毕,结果错误
- 代码异常终止
进程正常终止:
main函数的return退出
exit:库函数
_exit :系统调用
注:使用 echo $? 命令可以查看上一次结束的进程退出码
进程异常终止:
ctrl+c,信号终止
exit和_exit函数
#include <unistd.h>
void _exit (int status);
exit和_exit不同之处
exit会执行用户自定义的清理函数,而_exit不会
exit会冲刷缓冲区,并关闭流等,而_exit不会
刷新缓冲区方式:
- \n
- fflush() eg:fflush(stdout) stdout标准输出
- 从main函数的return返回
- 调用exit函数会刷新缓冲区
进程等待
进程等待可以防止僵尸进程的产生
进程等待的方法:
pid_t wait (int* status)
status是一个出参,供调用者获取子进程的退出状态(不是退出码),不关心可以设置为NULL。
返回值:成功,返回子进程的pid
失败,返回-1
调用wait会导致父进程陷入阻塞状态,直到有一个子进程退出,则执行wait的逻辑之后退出
阻塞:当调用函数需要等待一定条件成熟的时候,如果条件不成熟,则一直等待;如果条件成熟,则执行函数逻辑之后正常返回
非阻塞:当调用函数需要等待一定条件的时候,如果该条件不成熟,则直接返回,如果该条件成熟,则执行调用函数的逻辑之后再返回。
pid_t waitpid(pid_t pid,int* status,int options)
pid 要等待哪个子进程
- pid= -1 等待任意子进程退出,与wait函数等效
- pid>0 等待指定子进程
status 退出的子进程的退出状态
options 设置当前的waitpid 是阻塞还是非阻塞的
- WNOHANG:非阻塞
若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID
- 0 :阻塞
获取子进程的status
status 是一个输出型参数,由操作系统填充
如果传递NULL,表示不关心子进程的退出状态信息。否则操作系统会根据该参数,将子进程的退出状态信息反馈给父进程。
status是一个四个字节的数据,但是只用了低两个字节
正常退出:只用了这两个字节当中的高8位,来表示进程的退出码
正常退出的时候查看退出码的方法 ((status>>8)&0xff)
异常退出:只用了这两个字节当中的低8位
高的第8位 表示是否产生coredump标志位
低的7位,表示异常信号
查看coredump标志位:(status>>7)&0x1
查看终止信号:status&0x7f