通过调用fork和exec函数都能创建新的进程,但两者有着本质的区别:fork函数拷贝了父进程的内存映像,而exec函数用用新的映像来覆盖调用进程的进程映像的功能。
一 fork函数
#include <unistd.h>
pid_t fork(void); //创建子进程成功时,向子进程返回0,并将子进程的进程ID返回给父进程
//创建失败时,返回-1,并将errno设置为EAGAIN
返回值是允许父进程和子进程区别自己并执行不同代码的关键特征。
#include <stdio.h>
#include
<unistd.h>
#include
<sys/types.h>
int
main(
void
){
pid_t childpid;
//子进程的ID
childpid
=
fork();
//创建子进程
if
(childpid==-
1
){
//创建子进程失败
perror(
"
Failed to fork
"
);
return
1
;
}
if
(childpid==
0
){
//创建子进程成功
printf(
"
I am child %ld\n
"
,(
long
)getpid());
//打印子进程的ID
}
else
{
printf(
"
I am parent %ld\n
"
,(
long
)getpid());
//打印父进程的ID
}
}
二 exec函数
有六种不同形式的exec函数,如下:
#include <unistd.h>
int
execl(
const
char
*path,
//进程映像文件的路径名,可以是全限定路径名,也可以是相对于当前目录的路径名
const
char
*arg,...
);
int
execle(
const
char
*path,
const
char
*arg,...,
char *const envp[]
);
//最后一个参数必须以空指针(NULL)作结束
int
execlp(
const
char
*file,
const
char
*arg,...
);
int
execv(
const
char
*path,
char
*
const
argv[]);
//参数数组,用来存放指向你的字符串参数的指针数组
int
execve(
const
char
*path,
char
*
const
argv[],
char
*
const
envp[]);
int
execvp(
const
char
*file,
char
*
const
argv[]);
execv开头的函数是把参数以"char *argv[]"这样的形式传递命令行参数。而execl开头的函数采用了我们更容易习惯的方式,把参数一个一个列出来,然后以一个NULL
表示结束,也可以写成(char *)0。
如果创建子进程不成功,所有的exec函数都返回-1,并设置errno,以下是errno的类型和原因。
E2BIG:新进程的参数表和环境表长度以系统所允许的ARG_MAX字节的限制要长
EACCES:对新进程路径前缀中目录的搜寻权限被否定,新进程映像文件的执行权限被否定,或者新进程映像文件不是正常的文件,且不能被执行
EINVAL:新进程映像文件有恰当的权限,且以可识别可执行的二进制格式出现
ELOOP:在对参数path或file进行解析时存在循环
ENAMETOOLONG:path或file的长度超出了PATH_MAX的范围,或者路径名组件比NAME_MAX要长
ENOENT:path或file组件命名的不是一个现存的文件,或者path或file为空字符串
ENOEXEC:映像文件有恰当的访问权限,但它的格式不可识别(不适用于execlp或execvp)
ENOTDIR:映像文件路径前缀的组件不是一个目录
int
main(
int
argc,
char
*argv[],
char
*
envp[])
{
char
*arg[]={
"
ls
"
,
"
-a
"
,NULL};
if
(fork()==
0
)
{
printf(
"
execl...........\n
"
);
if
(execl(
"
/bin/ls
"
,
"
ls
"
,
"
-a
"
,NULL)<
0
)
{
fprintf(stderr,
"
execl failed:%s
"
,strerror(errno));
return
-
1
;
}
}
if
(fork()==
0
)
{
printf(
"
execv...........\n
"
);
if
(execv(
"
/bin/ls
"
,arg)<
0
)
{
fprintf(stderr,
"
execl failed:%s\n
"
,strerror(errno));
return
-
1
;
}
}
if
(fork()==
0
)
{
printf(
"
execlp...........\n
"
);
if
(execlp(
"
ls
"
,
"
ls
"
,
"
-a
"
,NULL)<
0
)
{
fprintf(stderr,
"
execl failed:%s
"
,strerror(errno));
return
-
1
;
}
}
if
(fork()==
0
)
{
printf(
"
execvp...........\n
"
);
if
(execvp(
"
ls
"
,arg)<
0
)
{
fprintf(stderr,
"
execl failed:%s\n
"
,strerror(errno));
return
-
1
;
}
}
if
(fork()==
0
)
{
printf(
"
execle...........\n
"
);
if
(execle(
"
/bin/ls
"
,
"
ls
"
,
"
-a
"
,NULL,envp)<
0
)
{
fprintf(stderr,
"
execl failed:%s
"
,strerror(errno));
return
-
1
;
}
}
if
(fork()==
0
)
{
printf(
"
execve...........\n
"
);
if
(execve(
"
/bin/ls
"
,arg,envp)<
0
)
{
fprintf(stderr,
"
execl failed:%s\n
"
,strerror(errno));
return
-
1
;
}
}
return
0
;
}

