本文研究的主要是Linux进程函数fork(),vfork(),execX()的相关内容,具体介绍如下。
函数fork()
fork函数:创建一个新进程
1、fork()成功后,将为子进程申请PCB和用户内存空间。
2、子进程会复制父进程用户空间的所有数据(代码段、数据段、BSS、堆、栈),文件描述符。
3、复制父亲进程PCB中绝大多数信息。
4、虽然子进程复制了文件描述符,而对于文件描述符相关的文件表项(struct file结构),则采用共享的方式。
一个实例:
?
#include <unistd.h> //fork fuction
#include <fcntl.h> //file operator
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h> //exit fuction
#include <string.h>
int
main() {
pid_t pid;
int
i=1;
int
status;
char
*ch1=
"hello"
,*ch2=
"world"
,*ch3=
"IN"
;
int
fd;
if
((fd=open(
"fork.txt"
,O_RDWR|O_CREAT,0644))==-1) {
perror
(
"not open"
);
exit
(EXIT_FAILURE);
}
if
(write(fd,ch1,
strlen
(ch1))==-1) {
//write in fork.txt
perror
(
"not write"
);
exit
(EXIT_FAILURE);
}
if
((pid=fork())==-1) {
perror
(
"fork error"
);
exit
(EXIT_FAILURE);
}
else
if
(pid==0) {
//son process
int
i=2;
//change i
printf
(
"child:i=%d\n"
,i);
if
(write(fd,ch2,
strlen
(ch2))==-1)
perror
(
"child write"
);
return
0;
}
else
{
sleep(1);
printf
(
"parent:i=%d\n"
,i);
if
(write(fd,ch3,
strlen
(ch3))==-1)
perror
(
"child write"
);
wait(&status);
return
0;
}
}
运行:
?
[root@localhost linux]# gcc -o fork fork.c
[root@localhost linux]# ./fork
child:i=2
parent:i=1
可以看到在子进程中改变了i的值,然而父进程i仍为1,所以说子进程和父进程有自己的用户空间。而打开所创建的fork.txt可以得到hellowordIN,父子进程共同对一个文件操作写入的数据是不交叉覆盖的,说明父子进程共享文件偏移,一次共享文件表项。
函数vfork()
与fork()函数不同,vfork()函数在创建进程是并不复制父进程的地址空间,而是在必要的时候才申请新的存储空间,因此使得vfork()更有效率。
特别注意的是vfork()是共享父进程的代码以数据段。
一个例子:
?
#include <unistd.h> //fork fuction
#include <fcntl.h> //file operator
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h> //exit fuction
#include <string.h>
int
i=10;
int
main() {
pid_t pid;
if
((pid=fork())==-1) {
perror
(
"fork error"
);
exit
(EXIT_FAILURE);
}
else
if
(pid==0) {
//son process
i++;
printf
(
"child:i=%d\n"
,i);
_exit(0);
}
else
{
sleep(1);
printf
(
"parent:i=%d\n"
,i);
return
0;
}
}
注意:上面的代码中回收子进程用的是_exit(0),如果用return 0;的话它会回收用户空间,因此在父进程调用的时候会出现段错误。
下面是调用输出结果:
?
如果以fork()创建则会输出:
[root@localhost linux]# ./fork
child:i=11
parent:i=10
如果改为vfork(),则:
child:i=11
parent:i=11
函数exec X()系列函数
用fork()函数创建紫禁城后,如果希望在当前子进程中运行新的程序,则可以调用execX系列函数。
注意:当进程调用exec函数后,该进程的用户空间资源完全有新程序代替。
这些函数的区别在于:
1、指示新程序的位置是路径还是文件名
2、在使用参数时是使用参数列表哈市使用argv[]数组
3、后缀有l(list)表示使用参数列表,v表示使用argv[]数组
具体如下所示:
?
#include<unistd.h>
int
execl(
const
char
*pathname,
const
char
*arg0,...
/*(char *) 0 */
);
int
execv(
const
char
*pathname,
char
*
const
argv[]);
int
execle(
const
char
*pathname,
const
char
*arg0,...
/*(char *) 0
,char *const envp[] */
);
int
execve(
const
char
*pathname,
char
*
const
argv[],
char
*
const
envp[]);
int
execlp(
const
char
*filename,
const
char
*arg0,...
/*(char *) 0*/
);
int
execvp(
const
char
*filename,
char
*
const
argv[]);
int
fexecve(
int
fd,
char
*
const
argv[],
char
*
const
evnp[]);
一个实例:
?
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int
main(
int
argc ,
char
* argv[]) {
pid_t pid;
if
((pid=fork())==-1)
printf
(
"error"
);
else
if
(pid==0)
execl(
"/bin/ls"
,
"ls"
,
"-l"
,argv[1],(
char
*)0);
else
printf
(
"father ok\n"
);
}
运行可以看到在子进程中执行了ls命令。
?
[yqtao@localhost linux]$ gcc -o exec execX.c
[yqtao@localhost linux]$ ./exec /home father ok
//execlp()函数使用
?
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int
main(
int
argc ,
char
* argv[]) {
execlp(
"ls"
,
"ls"
,
"-l"
,
"/home"
,(
char
*)0);
}
//execv()函数的使用
?
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int
main(
int
argc ,
char
* argv[]) {
char
* argv1[]={
"ls"
,
"-l"
,
"/home"
,0};
execv(
"/bin/ls"
,argv1);
}
ecvp()会从环境变量PATH所指定的目录中查找文件名作为第一个参数,第二个及以后的参数由参数列表,注意最后一个成员必须为NULL
?
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int
main(
int
argc ,
char
* argv[]) {
char
* argv1[]={
"ls"
,
"-l"
,
"/home"
,0};
execvp(
"ls"
,argv1);
}
总结
以上就是本文关于深入解读Linux进程函数fork(),vfork(),execX()的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
原文链接:http://blog.csdn.net/taoyanqi8932/article/details/52778015
原创文章,作者:SKCNS,如若转载,请注明出处:http://www.wangzhanshi.com/n/6399.html