进程替换
exec:替换进程实体(物理内存)
- fork,写时拷贝,通过exec产生新的进程主体。
- 只有一个进程,exec,产生新程序替换原程序所有代码指令,进程不变。
#include <unistd.h>
extern char **environ;
//库函数
//man 3 exec
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[]);//This function first appeared in glibc 2.11, is a GNU extension.
//系统调用函数,库函数的实现依赖于系统调用函数
//man 2 execve
int execve(const char *filename, char *const argv[], char *const envp[]);
execl | 默认当前文件夹或指定路径,命令行函数参数列表,最后一个可变参数为NULL | 库函数 |
---|---|---|
execlp | 默认环境变量或指定路径,命令行函数参数列表,最后一个可变参数为NULL | 库函数 |
execle | 默认当前文件夹或指定路径,命令行函数参数列表,最后一个可变参数为NULL 指定新环境变量表 | 库函数 |
execv | 默认环境变量或指定路径,命令行参数列表数组,数组的最后一个可变参数也应为NULL | 库函数 |
execvp | 默认环境变量或指定路径,命令行参数列表数组,数组的最后一个可变参数也应为NULL | 库函数 |
execvpe | 默认当前文件夹或指定路径,命令行参数列表数组,数组的最后一个可变参数也应为NULL 指定新环境变量表 | 库函数 |
execve | 系统调用函数,同execvpe() | 系统调用函数 |
l | 命令行函数参数列表 |
---|---|
v | 命令行参数列表数组 |
p | 指定新环境变量表 |
- 示例
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
printf("main: %d\n",getpid());
for(int i=0;i<argc;i++)
{
printf("%s ",argv[i]);
}
printf("\n");
}
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("exec: %d\n",getpid());
execl("main","./main","hello world",(char*)NULL);
//execlp("main","./main","hello world",(char*)NULL);//未指定路径,只在默认环境变量查找
//execlp("./main","./main","hello world",(char*)NULL);//指定路径可执行
printf("exec:error\n");
}
[root@localhost zombie]# ./execl
exec: 7354
main: 7354 #同一个进程
./main hello world
[root@localhost zombie]# ./execlp #只在默认环境变量查找,error
exec: 7567
exec:error
父子进程,共享fork之前打开的文件的读写偏移量
子进程exec,PCB不变,读写偏移量不清空。
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
printf("exec:%d\n",getpid());
char buf[128] = {};
int fd = atoi(argv[1]);//传入的第二个命令行参数位文件描述符,将其转换为整型
read(fd,buf,5);
printf("exec:%s\n",buf);
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main()
{
int fd = open("a.txt", O_RDWR);
assert(fd!=-1);
pid_t n = fork();
assert(n!=-1);
if(n==0)
{
printf("child:%d\n",getpid());
char fd1[128] = {};
sprintf(fd1,"%d",fd);//将文件描述符转为字符串,作为第二个命令函参数
execl("child","./child",fd1,(char*)NULL);//第一个命令行参数为,执行命令
printf("exec:error\n");
}
else
{
printf("parent:%d\n",getpid());
sleep(1);
char buf[128] = {};
read(fd,buf,5);
printf("parent:%s\n",buf);
}
close(fd);
exit(0);
}
parent:10583 #父进程
child:10584 #子进程
exec:10584 #子进程exec
exec:hello #exec读取文件
parent:world #父进程读取文件