现在的位置: 首页 > 综合 > 正文

linux下 fork题 转

2013年09月05日 ⁄ 综合 ⁄ 共 3351字 ⁄ 字号 评论关闭

Linux下fork()函数浅析

实验环境:Ubuntu  3.5.0-32-generic

头文件:

        #include <unistd.h>

        #include <sys/types.h>

函数原型:

 pid_t fork(void);
(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中)
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1

     fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

     一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。当子进程被调度得以执行时,其从程序中fork()语句下一条指令开始执行。

     由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程
id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。 对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id。(进程id 0总是由交换进程使用,所以一个子进程的进程id不可能为0 )。

Program1:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char * argv[])  
  7. {  
  8.     pid_t pid = 0;  
  9.   
  10.     printf("Before fork!--with \"\\n\"\n");  
  11.     printf("Before fork!--without \"\\n\"");  
  12.   
  13.     pid = fork();  
  14.   
  15.     if(pid == 0){  
  16.         printf("Child process!\n");  
  17.         pid_t pid_child = getpid();  
  18.         printf("Pid = %d\n",pid_child);  
  19.     }  
  20.   
  21.     else if(pid > 0){  
  22.         printf("Parent process!\n");  
  23.         pid_t pid_parent = getpid();  
  24.         printf("Pid = %d\n",pid_parent);  
  25.     }  
  26.   
  27.     else{  
  28.         printf("fork failure!\n");  
  29.     }  
  30.   
  31.     exit(0);  
  32. }  

Output:

程序浅析:

        在父进程中利用fork()系统调用生成子进程,此时父进程pid_parent = 3804,子进程pid_child = 3805;生成子进程后,父进程继续执行输出父进程pid,到遇见exit(0)后父进程退出,并退出Linux控制台。调度函数调度执行子进程,子进程在从程序fork语句下一语句开始执行,输出子进程pid,直到遇见exit(0)结束。

        在程序中字符串"Before fork!--with "\n""与字符串"Before fork--without "\n""的输出语句均在原程序中fork语句前执行,但前者只在父进程中输出一次,而后者在父、子进程都有输出一次,主要在于输出语句“printf”的实现中对输出缓存的处理,输出语句中的换行符"\n"会强制刷新输出缓存,故带换行符的输出语句只在父进程中输出一次,而后者在父进程结束后仍在输出缓存中保存,在子进程执行至输出语句printf("Child process!\n")时一并输出。

Program2:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char * argv[])  
  7. {  
  8.     pid_t pid = 0;  
  9.     int count = 13;  
  10.   
  11.     pid = fork();  
  12.   
  13.     if(pid == 0){  
  14.         sleep(1);  
  15.         count = 31;  
  16.         printf("Child process!\nPid = %d\n",getpid());  
  17.     }  
  18.       
  19.     else if(pid > 0){  
  20.         wait(NULL);  
  21.         printf("Parent process!\nPid = %d\n",getpid());  
  22.     }  
  23.   
  24.     else{  
  25.         printf("Fork error!\n");  
  26.     }  
  27.   
  28.     printf("There are %d apples!\n",count);  
  29.   
  30.     exit(0);  
  31. }  

Output:

        wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status
返回,
而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status 可以设成NULL。

        在本程序中,父进程调用fork()函数创建子进程3837后,父进程继续执行,当执行到wait(NULL);时,阻塞自己,调度函数调度子进程开始执行,子进程结束后,父进程从阻塞前的地方开始继续执行,此时子进程对count值的改变并未传递至父进程,输出count值,直到exit(0)结束。

Program 3:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char * argv[])  
  7. {  
  8.     fork();  
  9.     fork()&&fork()||fork();  
  10.     fork();  
  11.     exit(0);  
  12. }  

以上程序共有多少个进程?

共创建19个新进程,与父进程一共20个进程。

我们对以上程序作一些修改,让每个进程执行均有一个标志性的输出,即可验证我们的猜想!

Program 3‘:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <sys/types.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc,char *argv[])  
  7. {  
  8.     fork();  
  9.     fork() && fork() || fork();  
  10.     fork();  
  11.   
  12.     printf("End of process!\n");  
  13.     exit(0);  
  14. }  

Output:

           由以上程序可见,共执行输出语句20次,即我们的分析得以验证:共20个进程。

        *由于某些原因,先前所用Ubuntu系统故障,此程序在centos平台完成测试。 

附录:

        wait()与waitpid()浅析

        sleep()系统调用浅析

抱歉!评论已关闭.