深入解读Linux进程函数fork(),vfork(),execX()
本文研究的主要是Linux进程函数fork(),vfork(),execX()的相关内容,具体介绍如下。
fork函数:创建一个新进程
1、fork()成功后,将为子进程申请PCB和用户内存空间。
2、子进程会复制父进程用户空间的所有数据(代码段、数据段、BSS、堆、栈),文件描述符。
3、复制父亲进程PCB中绝大多数信息。
4、虽然子进程复制了文件描述符,而对于文件描述符相关的文件表项(structfile结构),则采用共享的方式。
一个实例:
#include//forkfuction #include //fileoperator #include #include #include //exitfuction #include intmain(){ pid_tpid; inti=1; intstatus; char*ch1="hello",*ch2="world",*ch3="IN"; intfd; if((fd=open("fork.txt",O_RDWR|O_CREAT,0644))==-1){ perror("notopen"); exit(EXIT_FAILURE); } if(write(fd,ch1,strlen(ch1))==-1){//writeinfork.txt perror("notwrite"); exit(EXIT_FAILURE); } if((pid=fork())==-1){ perror("forkerror"); exit(EXIT_FAILURE); } elseif(pid==0){//sonprocess inti=2;//changei printf("child:i=%d\n",i); if(write(fd,ch2,strlen(ch2))==-1) perror("childwrite"); return0; } else{ sleep(1); printf("parent:i=%d\n",i); if(write(fd,ch3,strlen(ch3))==-1) perror("childwrite"); wait(&status); return0; } }
运行:
[root@localhostlinux]#gcc-oforkfork.c [root@localhostlinux]#./fork child:i=2 parent:i=1
可以看到在子进程中改变了i的值,然而父进程i仍为1,所以说子进程和父进程有自己的用户空间。而打开所创建的fork.txt可以得到hellowordIN,父子进程共同对一个文件操作写入的数据是不交叉覆盖的,说明父子进程共享文件偏移,一次共享文件表项。
与fork()函数不同,vfork()函数在创建进程是并不复制父进程的地址空间,而是在必要的时候才申请新的存储空间,因此使得vfork()更有效率。
特别注意的是vfork()是共享父进程的代码以数据段。
一个例子:
#include//forkfuction #include //fileoperator #include #include #include //exitfuction #include inti=10; intmain(){ pid_tpid; if((pid=fork())==-1){ perror("forkerror"); exit(EXIT_FAILURE); } elseif(pid==0){//sonprocess i++; printf("child:i=%d\n",i); _exit(0); } else{ sleep(1); printf("parent:i=%d\n",i); return0; } }
注意:上面的代码中回收子进程用的是_exit(0),如果用return0;的话它会回收用户空间,因此在父进程调用的时候会出现段错误。
下面是调用输出结果:
如果以fork()创建则会输出: [root@localhostlinux]#./fork child:i=11 parent:i=10 如果改为vfork(),则: child:i=11 parent:i=11
用fork()函数创建紫禁城后,如果希望在当前子进程中运行新的程序,则可以调用execX系列函数。
注意:当进程调用exec函数后,该进程的用户空间资源完全有新程序代替。
这些函数的区别在于:
1、指示新程序的位置是路径还是文件名
2、在使用参数时是使用参数列表哈市使用argv[]数组
3、后缀有l(list)表示使用参数列表,v表示使用argv[]数组
具体如下所示:
#includeintexecl(constchar*pathname,constchar*arg0,.../*(char*)0*/); intexecv(constchar*pathname,char*constargv[]); intexecle(constchar*pathname,constchar*arg0,.../*(char*)0 ,char*constenvp[]*/); intexecve(constchar*pathname,char*constargv[],char*constenvp[]); intexeclp(constchar*filename,constchar*arg0,.../*(char*)0*/); intexecvp(constchar*filename,char*constargv[]); intfexecve(intfd,char*constargv[],char*constevnp[]);
一个实例:
#include#include #include intmain(intargc,char*argv[]){ pid_tpid; if((pid=fork())==-1) printf("error"); elseif(pid==0) execl("/bin/ls","ls","-l",argv[1],(char*)0); else printf("fatherok\n"); }
运行可以看到在子进程中执行了ls命令。
[yqtao@localhostlinux]$gcc-oexecexecX.c [yqtao@localhostlinux]$./exec/homefatherok
//execlp()函数使用
#include#include #include intmain(intargc,char*argv[]){ execlp("ls","ls","-l","/home",(char*)0); }
//execv()函数的使用
#include#include #include intmain(intargc,char*argv[]){ char*argv1[]={"ls","-l","/home",0}; execv("/bin/ls",argv1); }
ecvp()会从环境变量PATH所指定的目录中查找文件名作为第一个参数,第二个及以后的参数由参数列表,注意最后一个成员必须为NULL
#include#include #include intmain(intargc,char*argv[]){ char*argv1[]={"ls","-l","/home",0}; execvp("ls",argv1); }
以上就是本文关于深入解读Linux进程函数fork(),vfork(),execX()的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。