成都网站建设哪个好,青岛app开发公司,沈阳网站建设成创,做app网站需要什么技术支持fork与进程等待 引言forkfork创建子进程的过程写时拷贝 进程等待waitwaitpid阻塞等待与非阻塞轮询 总结 引言
fork函数在Linux中是一个非常重要的系统调用接口#xff01;它用于在当前的已有进程中创建一个新的进程#xff08;子进程#xff09;。再由父子进程并发地执行不… fork与进程等待 引言forkfork创建子进程的过程写时拷贝 进程等待waitwaitpid阻塞等待与非阻塞轮询 总结 引言
fork函数在Linux中是一个非常重要的系统调用接口它用于在当前的已有进程中创建一个新的进程子进程。再由父子进程并发地执行不同地代码块就相当于父子进程给子进程派了一块代码让他去执行。 在子进程执行完代码块后应该给父进程一个发聩这个时候就需要父进程去等待子进程然后回收子进程以免形成内存泄漏等问题。 接下来就来详细地介绍fork函数以及进程等待
fork
fork可以从当前进程中创建一个新进程已有的进程就是父进程新进程就是子进程父进程与子进程并发地执行不同的代码块
#include stdio.h
#include unistd.h
#include sys/types.hint main()
{pid_t rid 0;rid fork();if(rid 0){perror(fork:);}else if(rid 0) //子进程{printf(i am child\n);}else //父进程(rid 0){printf(i am parent\n);}return 0;
}fork创建子进程的过程
在创建子进程时 操作系统会给子进程分配新的内存块与内核数据结构 然后父进程的部分数据被拷贝到子进程 然后子进程会被操作系统添加到调度列表中 最后会分别返回值给父子进程对父进程返回子进程的pid对子进程返回0
#include stdio.h
#include unistd.h
#include sys/types.hint main()
{pid_t rid 0;int a 10;printf(before: %d\n, a); rid fork(); //创建子进程a;printf(rid: %d: after: %d\n, rid, a);if(rid 0) //子进程{a;printf(child: %d\n, a);}else if(rid 0) //父进程{a2;printf(parent: %d\n, a);}return 0;
}在这段代码中定义了一个变量a我们可以通过这个变量a的变化来验证fork创建新进程的过程
首先打印了一遍before此时a的值为10。说明这时只有父进程一个执行流在执行代码 然后发现after打印了两遍两遍a的值都是11由父子进程分别打印。这首先说明在fork之后有父子进程两个执行流在执行代码。并且在创建子进程时子进程获取到了父进程之前的变量a所以两个执行流在这里打印出的值都是11 然后if_else对代码进行了分流父进程打印a2后的结果13子进程打印a后的结果12。说明进程之间是独立的他们有自己的进程地址空间与页表转化到不同的物理内存对自己进程中数据的改变不会影响对方进程。 需要注意的是父子进程的调度先后完全由调度器决定。
写时拷贝
通过上面的介绍我们知道在创建子进程时父进程要将自己的数据拷贝给子进程。但是对于代码或者子进程没有进行修改的数据在物理内存中在将这些数据存储一份显然是浪费内存空间的。
所以父子进程在拷贝数据是是以写时拷贝的方式来进行的 当创建子进程时父进程将自己的进程地址空间与页表拷贝给子进程即父子进程的数据段和代码段在通过页表映射后指向同一块物理内存
而如果子进程中会对一些数据做修改时就会发生写时拷贝。即将要修改的数据拷贝一份到另外的物理空间页表的转化关系也指向这块新的物理空间再由子进程对其进行修改
通过这样的写时拷贝的方式就可以减少内存的浪费。
进程等待
子进程退出后父进程应该获取子进程的退出状态看看子进程是否正常退出如果出现异常的错误码是什么 父进程也应该回收子进程的资源如果子进程的资源没有被回收就会造成内存泄漏 没有被父进程回收的子进程就会成为 “僵尸进程”无法被杀死。
父进程可以通过wait或waitpid函数来对子进程进行等待
wait
pid_t wait(int* status) 用于等待任一子进程 等待成功返回子进程pid等待中出错返回-1errno被设置 参数为输出型参数用于获取子进程的退出状态由操作系统填充若不关心返回状态参数设为NULL即可。
在等待结束后可以通过 WIFEXITED(status);查看进程是否是正常退出若为正常终止子进程则为真 通过 WEXITSTATUS(status);查看进程的退出码若WIFEXITED返回真提取子进程退出码
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/wait.hint main()
{pid_t rid 0;rid fork();if(rid 0) //子进程{printf(i am child\n);sleep(5);}else if(rid 0) //父进程{printf(i am parent\n);int status 0;pid_t ret 0;ret wait(status); //等待if(WIFEXITED(status) ! 0 ret rid) //如果等待成功打印子进程退出码{printf(child return :%d\n, WEXITSTATUS(status));}else{return 1;}}return 0;
}waitpid
pid_t waitpid(pid_t pid, int *status, int options); 可以等待任一子进程也可以用于等待指定子进程。等待成功返回子进程pid等待中出错返回-1errno被设置
第一个参数pid表示指定要等待子进程的pid若要等待任一子进程则传参-1 第二个参数为输出型参数参数为输出型参数用于获取子进程的退出状态由操作系统填充若不关心返回状态参数设为NULL即可 第三个参数为等待状态有多种选项当设置为WNOHANG:表示若pid指定的子进程没有结束则waitpid函数返回0不予以等待即非阻塞等待。
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/wait.hint main()
{pid_t rid 0;rid fork();if(rid 0){printf(i am child\n);sleep(5);}else if(rid 0){printf(i am parent\n);int status 0;pid_t ret 0;ret waitpid(rid, status, 0); //阻塞式等待pid为rid的子进程if(WIFEXITED(status) ! 0 ret rid){printf(child return :%d\n, WEXITSTATUS(status));}else{return 1;}}return 0;
}阻塞等待与非阻塞轮询
在使用wait或waitpid进行进程等待时若子进程正在执行父进程就会阻塞式的等待子进程执行结束等待成功后再继续执行接下来的代码
int main()
{pid_t rid 0;rid fork();if(rid 0){int n 10;while(n--){printf(i am child, %d\n, n);sleep(1);}}else if(rid 0){int status 0;pid_t ret 0;ret waitpid(rid, status, 0); //阻塞式等待成功等待子进程后才会执行后面的代码if(WIFEXITED(status) ! 0 ret rid){printf(child return :%d\n, WEXITSTATUS(status)); }else{return 1;}}return 0;
}但是如果父进程阻塞等待子进程的时间过长就会影响代码的效率。 如果父进程在等子进程时发现子进程正在执行父进程可以选择不阻塞等待而是去执行别的代码隔一段时间去看看子进程有没有退出。这样的非阻塞轮询的方式可以提高代码的效率
非阻塞等待的方式可以通过waitpid函数的WNOHANG选项来实现
int main()
{pid_t rid 0;rid fork();if(rid 0){int n 10;while(n--){printf(i am child, %d\n, n);sleep(1);}}else if(rid 0){int status 0;pid_t ret 0;do //非阻塞轮询当成功等待时终止循环{ret waitpid(rid, status, WNOHANG);if(ret 0){printf(child is running, i do something...\n);sleep(1);}}while(ret 0); if(WIFEXITED(status) ! 0 ret rid){printf(child return :%d\n, WEXITSTATUS(status));}else{return 1;}}return 0;
}这样就实现了父进程在等待子进程期间也可以做一些事提高了效率这里的父子进程是并发进行的两个进程抢占显示器打印的先后是由调度器决定的所以不是很按顺序属于正常。
总结
到此关于fork函数与进程等待的知识就介绍完了
如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题欢迎大家在评论区提出
如果本文对你有帮助希望一键三连哦
希望与大家共同进步哦