OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » fork()和vfork()函数学习过程

共2条 1/1 1 跳转至

fork()和vfork()函数学习过程

高工
2018-01-06 10:55:02    评分
fork()函数:头文件:#include <unistd.h>函数原型:pid_t for(void);fork()函数用于派生出另一个进程,原有的进程成为父进程,新生成的进程成为子进程。父进程调用fork后返回值是子进程的ID,子进程调用fork后返回值是0,调用出错时,返回值为-1.下面看个fork函数创建进程的例子:[cpp] view plain copy
  1. #include <stdio.h>  

  2. #include <stdlib.h>  

  3. #include <unistd.h>  

  4.   

  5. int main(void) {  

  6.     pid_t pid;  

  7.     printf("PID before fork():%d\n", getpid());  

  8.       

  9.     pid = fork();  

  10.     if (pid == 0)  

  11.         printf("This is the child process.my PID:%d,parentPID:%d\n",\  

  12.                 pid, getpid());  

  13.     else if(pid > 0)  

  14.         printf("This is the parent process.my PID:%d,childPDI:%d\n",\  

  15.                 getpid(), pid);  

  16.     else {  

  17.         printf("fork error.\n");      

  18.         exit(1);  

  19.     }  

  20.     return 0;  

  21. }  

blob.png从测试结果可以看出,印证了我们上面说的,父进程返回的是子进程ID,子进程返回的是0.
刚开始学习进程的时候,一直不理解进程的运行过程到底是怎样的。不清楚fork函数的作用,第一篇参考资料的那个例子让我理解的比较清楚了:[cpp] view plain copy
  1. #include <stdlib.h>  

  2. #include <stdio.h>  

  3. #include <sys/types.h>  

  4. #include <unistd.h>  

  5.   

  6. int main(void) {  

  7.     pid_t pid;  

  8.     int count = 0;  

  9.     pid = fork();  

  10.   

  11.     printf("This is first,PID:%d.\n", pid);  

  12.     count++;  

  13.     printf("count=%d\n", count);  

  14.   

  15.     if (pid < 0) {  

  16.         printf("fork failed.\n");     

  17.         exit(1);  

  18.     }  

  19.     else if (pid == 0)  

  20.         printf("this is the child process.\n");  

  21.     else  

  22.         printf("this is the parent process.child PID:%d.\n", pid);  

  23.   

  24.     printf("this is second,PID:%d.\n", pid);  

  25.   

  26.     return 0;  

  27. }  

blob.png
实际上调用fork函数后分裂出了两个进程,而且它们分别执行互不干扰。一般情况下调用fork函数后父子进程谁先执行是未定的,取决于内核所使用的调度算法。从程序的结果就可以看出来,调用fork函数的部分确实执行了两遍,但是count的值一直都没有改变,这是因为父进程和子进程是分别执行的。
vfork()函数头文件:#include <unistd.h>函数原型:pid_t vfork(void);vfork函数也是创建进程的,但是它实际上也是调用了fork函数。调用vfork与调用fork的作用基本相同,但是差别还是挺大的。先看看下面两个例子:例子1:调用fork函数[cpp] view plain copy
  1. #include <stdio.h>  

  2. #include <stdlib.h>  

  3. #include <sys/types.h>  

  4. #include <unistd.h>  

  5. int globalVal = 5;  

  6.   

  7. int main(void) {  

  8.     pid_t pid;  

  9.     int val = 1, i;  

  10.   

  11.     pid = fork();  

  12.     if (pid == 0) {  

  13.         i = 3;  

  14.         while (i-- > 0) {  

  15.             printf("child process is running.\n");    

  16.             globalVal++;  

  17.             val++;  

  18.             sleep(1);  

  19.         }  

  20.         printf("child's globalVal = %d, val = %d.\n", globalVal, val);  

  21.     }  

  22.     else if (pid > 0) {  

  23.         i = 5;  

  24.         while (i-- > 0) {  

  25.             printf("parent process is running.\n");  

  26.             globalVal++;  

  27.             val++;  

  28.             sleep(1);  

  29.         }  

  30.         printf("parent glovalVal = %d, val = %d.\n", globalVal, val);  

  31.     }  

  32.     else {  

  33.         printf("fork failed.\n");     

  34.         exit(1);  

  35.     }  

  36.     return 0;  

  37. }  


测试结果:

blob.png例子2:调用vfork函数[cpp] view plain copy
  1. #include <stdio.h>  

  2. #include <stdlib.h>  

  3. #include <sys/types.h>  

  4. #include <unistd.h>  

  5. int globalVal = 5;  

  6.   

  7. int main(void) {  

  8.     pid_t pid;  

  9.     int val = 1, i;  

  10.   

  11.     pid = vfork();  

  12.     if (pid == 0) {  

  13.         printf("子进程开始了!!!\nn");  

  14.   

  15.         i = 3;  

  16.         while (i-- > 0) {  

  17.             printf("child process is running.\n");    

  18.             globalVal++;  

  19.             val++;  

  20.             sleep(1);  

  21.         }  

  22.         printf("child's globalVal = %d, val = %d.\n", globalVal, val);  

  23.   

  24.         printf("子进程结束了!!!\nn");  

  25.         exit(0);  

  26.     }  

  27.     else if (pid > 0) {  

  28.         printf("父进程开始了!!!\n");  

  29.   

  30.         i = 5;  

  31.         while (i-- > 0) {  

  32.             printf("parent process is running.\n");  

  33.             globalVal++;  

  34.             val++;  

  35.             sleep(1);  

  36.         }  

  37.         printf("parent glovalVal = %d, val = %d.\n", globalVal, val);  

  38.           

  39.         printf("父进程结束了!!!\n");  

  40.     }  

  41.     else {  

  42.         printf("fork failed.\n");     

  43.         exit(1);  

  44.     }  

  45.   

  46.     return 0;  

  47. }  




测试结果:
blob.png
从两个程序的测试结果可以看出几点区别来:
  • 调用vfork时,父进程被挂起,子进程运行完exec函数簇的函数或调用exit时解除父进程的挂起状态(要不然会进入死循环,开始我就是按照第一篇资料里那样,在子进程和父进程结束的后面什么都没有加结果进入死循环了,资料里是在父进程结束时调用了exit(0)个人感觉不是这样的,因为正常的情况是先执行子进程然后执行exit(0)结束子进程,接着就会执行父进程,然后父进程执行完了以后就会正常结束程序)。

  • vfork和fork还有一点不同的就是,调用vfork生成的子进程并不完全复制父进程的数据段,而是和父进程共享数据段。所以globalVal和val变量在子进程之后得到的值,进入父进程继续增加。

  • 调用vfork对于父进程的执行次序还是有限制的。


vfork和for分别与exec函数簇看了些资料,上面都说vfork函数通常是与exec函数簇一起使用的,用来创建执行另一个程序的新进程。由于数据共享的原因fork创建的进程只是父进程的一个副本,也可以利用exec函数在子进程中重新载入一个全新的进程,下面看看fork和vfork分别与exec结合的例子例子1:fork与exec[cpp] view plain copy
  1. #include <stdio.h>  

  2. #include <stdlib.h>  

  3. #include <unistd.h>  

  4.   

  5. int main(void) {  

  6.     pid_t pid = fork();  

  7.     switch(pid) {  

  8.     case 0:  

  9.         printf("子进程\n");  

  10.         execl("/bin/ls""ls""-l", NULL);  

  11.         break;  

  12.     case -1:  

  13.         printf("fork失败\n");  

  14.         exit(1);  

  15.         break;  

  16.     default:  

  17.         wait(NULL);  

  18.         printf("完成了\n");  

  19.         exit(0);  

  20.         break;  

  21.     }  

  22.     return 0;  

  23. }  


测试结果:
blob.png
例子2:vfork与exec函数[cpp] view plain copy
  1. #include <stdlib.h>  

  2. #include <stdio.h>  

  3. #include <unistd.h>  

  4. #include <sys/types.h>  

  5.   

  6. int main(void) {  

  7.     pid_t pid = vfork();  

  8.     if (pid == 0) {  

  9.         printf("This is the child process.\n");   

  10.         execl("/bin/ls""ls""-l", NULL);  

  11.     }  

  12.     else if (pid > 0) {  

  13.         wait(NULL);  

  14.         printf("This is the parent process.\n");  

  15.     }  

  16.     else {  

  17.         printf("vfork failed\n");     

  18.         exit(1);  

  19.     }  

  20.   

  21.     return 0;  

  22. }  


测试结果:
blob.png




专家
2018-01-06 19:29:44    评分
2楼

谢谢楼主分享源码。


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]