exec系列函数可以创建(启动)新进程,并替换原进程的进程映像。exec系列函数如下所示:
#include
int execl(const char *path, const char *arg, ...,(char *) NULL);
int execlp(const char *file, const char *arg, ...,(char *) NULL);
int execle(const char *path, const char *arg, ..., (char *) NULL, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
这些函数按参数个数是否可变,可以分为两类。
①execl()、execlp()、execle(),他们的特点是:
1)参数个数可变;
2)最后一个arg参数为(char *) NULL。
3)函数名中带字母“l”。
②execv()、execp()、execvp(),他们的特点是:
1)参数个数不可变;
2)第二个参数是一个字符串数组,数组的最后一个元素需是(char *) NULL。
3)函数名中带字母“v”。
按第一个参数的类型,可以分为两类。
①execlp()、execvp()、execvpe(),他们的特点是:
1)第一个参数名为“file”;
2)第一个参数为被调用(启动)的可执行文件名,函数会通过PATH环境变量搜索该可执行文件,如果该文件不在PATH定义的路径中,则需要使用全路径名。
3)函数名中带字母“p”,表是可以通过PATH环境变量搜索。
②execl()、execle()、execv(),他们的特点是:
1)第一个参数名为“path”;
2)第一个参数为被调用(启动)的可执行文件的路径名,无论PATH环境变量是否包含该可执行文件的路径。
3)函数名中不带字母“p”,表是不可以通过PATH环境变量搜索
示例1:
#include
#include
void exec1()
{
printf("enter exec1\n");
const char *path = "/bin/ps";//此处需要使用路径名
const char *arg = "ps";
const char *arg1 = "";
execl(path,arg, (char *) NULL);
printf("leave exec1\n");
}
void main()
{
printf("enter main\n");
exec1();
printf("leave main\n");
}
打印结果:
enter main
enter exec1
PID TTY TIME CMD
10305 pts/18 00:00:00 bash
11156 pts/18 00:00:00 ps
分析:函数execl执行成功之后原进程映像被“ps”程序替换,故原进程中的
printf("leave exec1\n");
printf("leave main\n");
这两句为执行。
示例2:
#include
#include
void exec2()
{
printf("enter exec2\n");
const char *file = "ps";//此处使用可执行文件名
const char *arg = "ps";
const char *arg1 = "";
execlp(file,arg, (char *) NULL);
printf("leave exec2\n");
}
void main()
{
printf("enter main\n");
exec2();
printf("leave main\n");
}
打印结果:
enter main
enter exec2
PID TTY TIME CMD
10305 pts/18 00:00:00 bash
11202 pts/18 00:00:00 ps
分析:函数execlp执行成功之后原进程映像被“ps”程序替换,故原进程中的
printf("leave exec2\n");
printf("leave main\n");
这两句为执行。
示例3:
#include
#include
void exec3()
{
printf("enter exec3\n");
const char *path = "/bin/ps";
const char *arg = "ps";
const char *arg1 = "";
char * const envp[] = {"/bin:/usr/bin",NULL};//此处环境变量参数可有可无。
execle(path,arg, (char *) NULL,NULL);
printf("leave exec3\n");
}
void main()
{
printf("enter main\n");
exec3();
printf("leave main\n");
}
打印结果:
enter main
enter exec3
PID TTY TIME CMD
10305 pts/18 00:00:00 bash
11216 pts/18 00:00:00 ps
分析:函数execle执行成功之后原进程映像被“ps”程序替换,故原进程中的
printf("leave exec3\n");
printf("leave main\n");
这两句为执行。
示例4:
#include
#include
void exec4()
{
printf("enter exec4\n");
const char *path = "ps";//"/bin/ps"
char *const argv[] = {"ps",NULL};
execv(path,argv);
printf("leave exec4\n");
}
void main()
{
printf("enter main\n");
exec4();
printf("leave main\n");
}
打印结果:
enter main
enter exec4
leave exec4
leave main
分析:由于函数execv第一个参数未使用路径名,故execv执行失败,创开启新进程。
示例5:
#include
#include
void exec5()
{
printf("enter exec5\n");
const char *file = "ps";
char *const argv[] = {"ps",NULL};
execvp(file,argv);
printf("leave exec5\n");
}
void main()
{
printf("enter main\n");
exec5();
printf("leave main\n");
}
打印结果:
enter main
enter exec5
PID TTY TIME CMD
10305 pts/18 00:00:00 bash
11246 pts/18 00:00:00 ps
分析:函数execvp执行成功之后原进程映像被“ps”程序替换,故原进程中的
printf("leave exec5\n");
printf("leave main\n");
这两句为执行。
示例6:
#include
#include
void exec6()
{
printf("enter exec6\n");
const char *file = "ps";
char *const argv[] = {"ps",NULL};
char * const envp[] = {"/bin:/usr/bin",NULL};
execvpe(file,argv,envp);
printf("leave exec6\n");
}
void main()
{
printf("enter main\n");
exec6();
printf("leave main\n");
}
打印结果:
enter main
enter exec6
PID TTY TIME CMD
10305 pts/18 00:00:00 bash
11258 pts/18 00:00:00 ps
分析:函数execvpe执行成功之后原进程映像被“ps”程序替换,故原进程中的
printf("leave exec6\n");
printf("leave main\n");
这两句为执行。
如果想要进程同时执行多个函数,可以调用fork函数创建一个与原进程完全分离的进程。这个系统调用复制当前进程,并在进程表中创建一个新的表项,该表项与原进程表项基本相同。新进程与原进程几乎一模一样,执行的代码也完全相同,但新进程有自己独立的数据空间、环境和文件描述符。fork函数的部分manual如下所示:
NAME
fork - create a child process
SYNOPSIS
#include
pid_t fork(void);
RETURN VALUE
On success, the PID of the child process is returned in the parent, and
0 is returned in the child. On failure, -1 is returned in the parent,
no child process is created, and errno is set appropriately.
fork用法介绍
#include
#include
int main()
{
pid_t pid;
pid = fork();
if(pid == -1){
printf("fork failed\n");
return 1;
}else if(pid){
printf("The father return value is %d\n",pid);
printf("The father pid is %d\n",getpid()); //获取进程id
printf("The father ppid is %d\n",getppid()); //获取父进程id
while(1);
}else{
printf("The child return value is %d\n",pid);
printf("The child pid is %d\n",getpid()); //获取进程id
printf("The child ppid is %d\n",getppid()); //获取父进程id
while(1);
}
return 0;
}
The father return value is 12002
The father pid is 12001
The father ppid is 10305
The child return value is 0
The child pid is 12002
The child ppid is 12001
系统调用wait可以挂起父进程,等待子进程结束。
NAME
wait, waitpid, waitid - wait for process to change state
SYNOPSIS
#include
#include
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
/* This is the glibc and POSIX interface; see
NOTES for information on the raw system call. */
使用示例
#include
#include
#include
#include
int main()
{
pid_t pid;
int status = 0;
pid = fork();
if(pid == -1){
printf("fork failed\n");
return 1;
}else if(pid){
printf("The father return value is %d\n",pid);
wait(&status);
printf("The father pid is %d\n",status);
printf("The father pid is %d\n",getpid());
printf("The father ppid is %d\n",getppid());
//while(1);
}else{
printf("The child return value is %d\n",pid);
printf("The child pid is %d\n",getpid());
printf("The child ppid is %d\n",getppid());
//while(1);
}
return 0;
}
The father return value is 12118
The child return value is 0
The child pid is 12118
The child ppid is 12117
The father pid is 0
The father pid is 12117
The father ppid is 10305