进程替换,不是创建一个新进程,而是将一个运行的进程替换为其他进程执行;PCB使用原进程的,只进行修改。并且,进程替换是与进程复制配合进行的。
在进程复制时,我们根据fork()的返回值对父子进程进行区分,使其进行不同操作。在使用进程替换后,我们就可以使新进程更加直接的执行我们想要做的操作。进程复制时,父子进程代码相同,父子进程要进行的操作在同一份代码中,根据逻辑判断才进行区分。对于父进程来说,子进程要执行操作的代码就是冗余的。使用进程替换,我们就可以将想要执行的新操作封装在一个新程序中,在原进程中只用调用进程替换函数,替换为新进程执行就可以了。
1、exec系列六个函数
函数中的“l” 指 进程运行所需参数需要全部罗列出,如:execl("/bin/ps","ps","-f",(char*)0)。//(char*)0或NULL是参数结束的标志。
函数中的“v”指 进程运行所需参数封装后传入,如:char* buff[]={"ps","-f",(char*)0},execv("/bin/ps",buff);
函数中的“p“指 该可执行程序的路径在系统环境变量PATH中存在,系统去PATH中寻找路径,查找可执行文件。
函数中的“e”指 环境变量,可从父进程中的main函数继承得到,也可以自设。
1.1、execl函数
int execl( const char * path, const char * arg,...);
以替换为 ps 命令为例:
第一个参数为 可执行程序的路径+程序名,后续为所需参数,程序名也是参数之一。execl若执行成功,则进程替换为 ps 命令执行;若不成功,则执行perror,输出当前错误信息。
在执行a程序后,进程替换为ps,完成了ps -f命令的功能。
1.2、execlp函数
int execlp( const char * file, const char * arg,...);
file为可执行文件名,无需给出路径,系统根据系统环境变量中的PATH路径,查找可执行文件。 后续参数仍需可执行文件名。
对于系统命令,可以直接使用;对于用户自定义文件,不在系统路径下,就需要将路径赋值到$PATH中(export PATH=$PATH:.,将当前路径加入PATH)。
1.3、execle函数
int execle( const char * path, const char * arg,..., char * const envp[]);
execle只相较于execl多了envp,envp为环境变量数组,可以自定义,也可以从父进程继承得到。
1.4、execv函数
int execv( const char * path, char * const argv[]);
path为可执行文件的路径(包括文件名),argv为封装起来的参数数组。
1.5、execvp函数
int execvp( const char * file, char * const argv[]);
可执行程序名+封装参数。
1.6、execve函数
int execve( const char * path, char * const argv[], char * const envp[]);
execl,execlp,execle,execv,execvp,execvpe都不是系统调用,而是对系统调用的封装。execve才是系统调用。int execve(const char* filename,char* const argv[],char* const envp[])。
2、fork+exec联用
父进程b:
所替换进程main:
argc为参数个数;argv中保存进程运行所需参数,也是父进程中传入的参数集。
运行结果: