进程创建:
fork函数:创建子进程
- 头文件:#include <unistd.h>
- pid_t fork(void)
- 返回值:子进程中返回0,父进程返回子进程pid,出错返回-1。
运行规则:
- 以父进程为模板,进行子进程的创建。
- 会把父进程的PCB拷贝一份,稍加修改,成为子进程的PCB。
- 会把父进程的虚拟地址空间拷贝一份,作为子进程的地址空间。
- fork返回会在父子进程中分别返回。(返回值:子进程中返回0,父进程返回子进程pid,出错返回-1。)在fork后面进行继续执行。
- 父子进程的执行顺序没有先后关系,全靠调度器来实现。
注:拷贝是写时拷贝(C++中知识):父子进程共用一份代码,各有独自的数据。父子进程是互相独立的。由于大部分内存空间可能被拷贝,创建进程的开销仍然非常高。(是和线程相比,同样,有的情况下,线程创建也非常高(和协程相比),因此开销的大小比较是要有比较标准的。)
fork调用失败的原因:1、内存不够 2、进程太多
getpid():获取进程的id;getppid():获取父进程的id
#include<stdio.h> #include<unistd.h> int main(){ pid_t ret =fork(); if(ret > 0){ //father int count=5; while(count>0){ printf("father %d\n",getpid()); sleep(1); } }else if(ret == 0){ //child while(1){ printf("child %d,%d\n",getpid(),getppid()); sleep(1); } }else{ perror("fork"); } return 0; }
进程终止:
进程终止方式:
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码没执行完,代码异常终止
代码执行完情况:
- main函数返回,返回值叫做进程的退出码,通过退出码表示运行结果是否运行结果正确。
注:退出码为0,表示结果正确。退出码为非零,表示结果不正确。
echo $?:查看上一个进程的退出码是多少。注:如果写return -1,查看到的结果是255
$?:是bash中的一个特殊的变量,这个变量表示上一个命令对应的退出码。
- 调用exit函数(库函数,本质上也是调用了_exit)
头文件:#include<stdlib.h>
exit(<参数>):退出码是<参数>,exit在任何函数中都可以使用,使进程终止。
注:实际工作尽量少用,发生意外退出时,如果 exit() 写的很多,很难查到问题。
exit 比 _exit 多的地方:1、exit关闭流并且刷新缓冲区(main函数也可以刷新缓冲区) 2、多调用了结束函数
- 调用_exit函数(系统调用)
头文件:#include<unistd.h>
实际还是 exit() 用的多。