进程创建
#include <unistd.h>
pid_t fork(void);//创建子进程
- 分配新的内存块和内核数据结构给子进程(创建task_struct)
- 将父进程部分数据结构内容拷贝至子进程(拷贝父进程的task_struct内容)
- 添加子进程到系统当中(分配新的内核堆栈、新的pid,再将子进程PCB添加到链表)
- fork返回,开始调度器调度
fork之前父进程独立执行,fork之后父子进程分别执行,谁先执行有调度器决定
- fork有两个返回值,父进程返回子进程的pid,子进程返回0
- 一个父进程有多个子进程,一个子进程有一个父进程,fork之后父进程需要知道那个子进程完成任务,所以父进程返回子进程的pid
- 当fork失败返回-1,PCB是要占内存的,当内存不够或者实际用户进程超过了限制fork会调用失败
- vfork也可以创建子进程,vfork创建的父子进程共享地址空间,fork创建的父子进程具有独立的地址空间
- vfork保证子进程先运行,调用exec或exit之后父进程才能被调度运行,fork父子进程分别执行,执行顺序由调度器决定
进程终止
#include <unistd.h>
void _exit(int status);
//status定义进程终止状态,父进程通过wait获取
//status仅有低8位可被父进程所用
#include <unistd.h>
void exit(int status);
进程等待
- 子进程退出,父进程不管不顾会造成僵尸进程,僵尸进程会造成内存泄漏,就算是”kill -9“也无法终止进程,因为无法杀死死去的进程
- 所以父进程需要知道子进程的任务完成如何,父进程可以通过进程等待的方式获取子进程资源和退出信息
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int* status);
//成功返回被等待进程的pid,失败返回-1
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int* status, int options);
//当pid>0时,只等待进程ID为pid的子进程,当pid=0时,等待同一个进程组中的任何子进程
//当pid=-1时,等待任何子进程,当pid<-1时,等待指定进程组的中的任何子进程
//options:WNOHANG非阻塞式,WUNTRACED阻塞式,WUNTRACED涉及到跟踪方面的知识,并且很少用
//当正常返回时waitpid返回收集到的子进程的pid
//当设置了WNOHANG,而调用中waitpid发现没有退出的子进程可收集,返回0
//当调用出错时,返回-1,此时errno设置成相应的值以指示错误所在
- status是一个输出性型参数,由操作系统填充
- 如果传递NULL,表示不关心子进程的退出状态信息
- WITFEXITED(status):查看子进程是否正常退出,若为正常终止子进程返回的状态,则为非零,否则为0
- WEXITSTATUS(status):查看进程退出码,若WIFEXITED非零,提取子进程退出码,否则这个值毫无意义
- 上述的WITFEXITED和WEXITSTATUS是宏,用来读取子进程退出状态
- status不能简单当做整形,可以当位图看待,只研究低16位,当正常终止时,status的8-15位代表退出码,0-6位为0,当异常退出时,0-6为为退出码
- 如果子进程已退出,调用wait/waitpid时,wait/waitpid会立即返回,并释放资源,获取子进程退出信息
- 如果子进程存在且正常运行,调用wait/waitpid时,进程可能会阻塞
- 如果不存在子进程,则立即出错返回
进程程序替换
- 用fork创建子进程后执行的是和父进程相同的程序,也可执行不同的代码分支,一般子进程和父进程做不同的事,否则这个子进程无意义,所以子进程调用exec函数替换子进程的程序和数据
- 当进程调用exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动列程开始执行
- 调用exec函数时并不创建新的进程,所以进程的id未改变
替换函数
int execl(const char *path, const char* arg, ...);
int execlp(const char *file, const char* arg, ...);
int execle(const char *path, const char* arg, ..., char* const envp[]);
int execv(const char *path, const char arg[], ...);
int execvp(const char *file, const char arg[], ...);
int execle(const char *path, const char arg[], ..., char* const encp[]);