Linux进程替换:fork与exec系列函数

0. 引言

进程是一个正在运行的程序,每一个进程都对应着一个 PCB (进程控制块),如图
在这里插入图片描述

进程替换操作不再重新产生新的 PCB,而是用新的进程替换掉旧的进程,只对原来的 PCB 做部分修改,如图
在这里插入图片描述

1. exec 系列函数

exec 系列函数总共7个,分为三组

#include <unistd.h>

//第一组,l->list,p->path,e->envp
int execl(const char *pathname, const char *arg, ..., (char*)NULL);
int execlp(const char *file, const char *arg, ..., (char*)NULL);
int execle(const char *pathname, const char *arg, ..., (char*)NULL, char *const envp[]);
//第二组,v->vector,p->path,e->envp
int execv(const char *pathname, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
//第三组,v->vector,e->envp
int execve(const char *pathname, char *const argv[], char *const envp[]);

参数介绍

  • pathname:新替换的程序的路径+名称
  • file:新替换的程序的名称
  • arg:传给新程序主函数的第一个参数,一般为程序名称,后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数
  • argv:传给新程序主函数的参数数组,把所有的arg写到一个数组中
  • envp:传给新程序主函数的环境变量

其中,前两组属于库函数,第三组属于系统调用,前两组函数的内部实现都是调用了最后一个函数。以 ps 替换当前进程为例,通过命令 which ps 查看 ps 命令的路径为 /usr/bin/ps,execl 的代码示例如下

//execl.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main(){
	printf("main pid=%d\n", getpid());
	//execl执行成功不返回,直接从新程序的主函数开始执行,只有失败才会返回错误码
	execl("/usr/bin/ps", "ps", "-fL", (char*)0);
	perror("exec error");
	exit(0);	
}

程序输出如下
在这里插入图片描述

可见,进程替换后新进程(ps)继承了原来进程的 pid。

//上面代码中的语句
execl("/usr/bin/ps", "ps", "-fL", (char*)0);
//可以用其他几个函数代替
//execlp
execlp("ps", "ps", "-fL", (char*)0);
//execle
char *myenvp[] = {"MYSTR=hello", "VAL=100", (char*)0};
execle("/usr/bin/ps", "ps", "-fL", (char*)0, myenvp);
//execv
char *myargv[] = {"ps", "-fL", (char*)0};
execv("/usr/bin/ps", myargv);
//execvp
char *myargv[] = {"ps", "-fL", (char*)0};
execvp("ps", myargv);
//execvpe
char *myargv[] = {"ps", "-fL", (char*)0};
char *myenvp[] = {"MYSTR=hello", "VAL=100", (char*)0};
execvpe("ps", myargv, myenvp);
//execve
char *myargv[] = {"ps", "-fL", (char*)0};
char *myenvp[] = {"MYSTR=hello", "VAL=100", (char*)0};
execve("/usr/bin/ps", myargv, myenvp);

2. fork 与 exec 配合使用创建全新进程

主程序 a 产生一个子进程,子进程用新程序 b 替换

//a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>

int main(){
	printf("main pid=%d\n", getpid());
	pid_t pid = fork();
	assert(pid != -1);
	if(pid == 0){
		char *myargv[] = {"b", "hello", "world", (char*)0};
		char *myenvp[] = {"MYSTR=nihao", "VAL=100", (char*)0};
		execve("./b", myargv, myenvp);
		perror("exec error");
		exit(0);
	}
	wait(NULL);
	printf("main over\n");
	exit(0);
}
//b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main(int argc, char *argv[], char *envp[]){
	printf("b pid=%d\n", getpid());
	printf("argc=%d\n", argc);
	for(int i = 0; i < argc; i++){
		printf("argv[%d]=%s\n", i, argv[i]);
	}
	for(int i = 0; envp[i] != NULL; i++){
		printf("envp[%d]=%s\n", i, envp[i]);
	}
	exit(0);
}

程序输出结果如下
在这里插入图片描述

可以看出,程序 a 的 pid=249556,运行过程中产生了 pid=249557 的子进程,该子进程被程序 b 替换并继承了 pid。同时,程序 b 也接收到了从程序 a 中传来的参数 myargv 和 myenvp,当程序 b 运行结束将返回码传给程序 a,程序 a 继续执行直至结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值