赞
踩
送给大家一句话:
人生中有些事,你不竭尽所能去做,你永远不知道你自己有多出色。—— 尾田荣一郎《海贼王》
通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,联系我们之前学习的进程,进程控制等概念。我们可以想要运行其他代码可以通过创建子进程来实现,但是这样也肯定是同一种语言,如果想要运行其他语言,那是不是有种方法可以调度一个进程来当做子进程呢???
我们开始今天的学习吧!
进程替换有六种以exec开头的函数,统称exec函数:
#include <unistd.h>`
int execl(const char *path, const char *arg, ...);//...代表可变参数 类似printf
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *filename, char *const argv[],char* const envp[]);
我们来进行一下使用,来看看:
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 printf("textexec ... begin!\n");
7
8 execl("/usr/bin/ls","ls","-l","-a",NULL);
9
10 printf("textexec ... end!\n");
11 return 0;
12 }
可以看到执行了ls -l -a
命令(最后的打印语句也没有进行),可是我执行的是我们的代码,怎么就运行了ls
这个程序呢?
原因就是:exec*系列函数可以执行起来新的程序,让进程通过exec函数把自己替换为一个全新的进程!
我们知道 进程 = 内核数据结构 + 代码和数据
,替换就是用新进程的代码与数据
替换之前的代码与数据
,注意不改变pid哦!
站在被替换进程的角度:本质就是这个程序别加载到内存里了!!!exec* 就类似一个Linux 上的加载函数。
而且我们不用关心exec*函数的返回值,只要替换成功了,就不会向后运行(也就用不到它的返回值了),只要继续运行那一定就是替换失败了!!!
那如果不想替换掉我们的程序,还想要打开一个新程序呢??? 我们接着向下看
方法很简单,我们通过fork函数创建一个子进程,让子进程来执行我们的新程序不就可以了吗!
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<stdlib.h> 4 #include<sys/types.h> 5 #include<sys/wait.h> 6 7 8 int main() 9 { 10 printf("textexec ... begin!\n"); 11 12 pid_t id = fork(); 13 if(id == 0) 14 { 15 //child 16 execl("/usr/bin/ls","ls","-l","-a",NULL); 17 exit(1); 18 } 19 20 int status = 0; 21 pid_t rid = waitpid(-1,&status,0); 22 23 if(rid > 0) 24 { 25 printf("father wait success,child exit code:%d \n",WEXITSTATUS(status)); 26 } 27 printf("testexec ... end!\n"); 28 29 return 0; 30 }
这个程序中:我们通过fork创建了一个子进程,然后在子进程中进行进程替换。这样应该就可以运行ls
命令还不会影响原本程序。来看效果:
那么这样以后,创建子进程就变得非常有用了。我们可以通过子进程来完成对应任务:
这些函数原型看起来很容易混,但只要掌握了规律就很好记。
l 表示列表 list
两个参数分别代表:
ls -a -l
所以我们传execl(“/usr/bin/ls” , “ls”,“-a”,“-l”) 。这样就像命令列表通过这些函数也可以进行执行我们缩写的程序!!!
v 表示数组 vector
这个方法就是把列表整合为一个数组,这样就直接传入一个数组(必须以NULL结尾!!!)就可以了:
char* const argv[] =
{
(char*)"ls",
(char*)"-a",
(char*)"-l",
(char*)"--color",
NULL
};
execv("/usr/bin/ls",argv);
是不是很想之前了解过的main函数参数!
带p含义是可以不传入文件路径,可以直接告诉exec*需要执行谁就可以了
本质就是:查找这个程序,系统会在系统环境变量PATH中的路径来寻找
char* const argv[] =
{
(char*)"ls",
(char*)"-a",
(char*)"-l",
(char*)"--color",
NULL
};
execvp("ls",argv);
这个 int execlp(const char *file, const char *arg, …) 同理!!!
execlp("ls" , "ls","-a","-l")
这个就就加上了环境变量,让我们支持自主传入
int execve(const char *filename, char const argv[],char const envp[]) 同理 !!!
这让我们可以传入环境变量给子进程!!!当然也会有一批来着"爷爷进程"bash的环境变量!
envp的含义是全体替换环境变量,所以会有以下情况:
char* const argv[] = { (char*)"ls", (char*)"-a", (char*)"-l", (char*)"--color", NULL }; //用全新的给子进程 char* const envp[] = { (char*)"HAHA=111111", (char*)"HEHE=222222", NULL }; //putenv("HAHA=111111") //putenv("HEHE=222222"); //老的环境变量稍微修改传给子进程 execvpe("./myprocess",argv , encp); //char** environ // execvpe("./myprocess",argv , environ);
根据上面的用法使用,我们可以总结一下:
函数名 | 参数格式 | 是否带路径 | 是否使用当前环境变量 |
---|---|---|---|
execl | 列表 | 不是 | 是 |
execlp | 列表 | 是 | 是 |
execle | 列表 | 不是 | 不是,需要自己组装环境变量 |
execv | 数组 | 不是 | 是 |
execvp | 数组 | 是 | 是 |
execve | 数组 | 不是 | 不是,需要自己组装环境变量 |
而且只有 execle 是系统调用!!!他们的关系如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。