【Linux】进程控制(exec函数族)的理解和使用

这篇具有很好参考价值的文章主要介绍了【Linux】进程控制(exec函数族)的理解和使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 进程程序替换是什么

我们直到一个进程被创建出来,OS会给它分配进程PCB,mm_struct,页表等信息,同时会将程序的代码和数据加载到物理内存是吧;
而进程程序替换就是:正在执行的进程本身的pcb,mm_struct,页表等信息不会发生改变,仅仅把一个新的程序代码和数据替换了原来进程的代码和数据;这就是进程程序的替换;


如下图:我们有个进程,在执行中,如果发生进程程序替换,只不过事把该进程的代码和数据从磁盘加载到了物理内存罢了,其他信息不会变化;
【Linux】进程控制(exec函数族)的理解和使用


进程程序替换并不会创建新的进程,它只会加载程序的代码和数据,去替换原来的进程!!!


2. 进程替换函数–exec族

#include <unistd.h>` //exec函数族的头文件
int execl(const char *path, const char *arg, ...);
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[]);
  1. 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回;
  2. 如果调用出错则返回-1;
  3. 所以exec函数只有出错的返回值而没有成功的返回值

这些函数原型看起来很容易混,但只要掌握了规律就很好记。

l(list) : 表示参数采用列表;
v(vector) : 参数用数组;
p(path) : 有p自动搜索环境变量PATH;
e(env) : 表示自己维护环境变量;


【Linux】进程控制(exec函数族)的理解和使用


最简单的程序替换程序:

int main()
{
  execl("/usr/bin/ls","ls","-a","-l",NULL); //程序替换函数
  printf("这段代码是在execl执行成功是不会执行的\n");
  return 0;
}

【Linux】进程控制(exec函数族)的理解和使用


而我们程序替换的本质:
【Linux】进程控制(exec函数族)的理解和使用


而我们的程序替换函数,通常不父进程去执行,而是交给子进程执行,因为这也子进程可以做它的事,父进程也可以做自己的事,由于进程之间的独立性,即使子进程去执行execl函数时候,替换的也是子进程的代码和数据,而父进程的代码和数据是不会被影响的;


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>

int main()
{
  pid_t pid = fork();

  if(pid == 0){
    //child process 
    execl("/usr/bin/ls","ls","-a","-l",NULL);
    //退出子进程
    exit(0);
  }
  //父进程执行的代码
  wait(NULL);
  printf("i am father[%d] ,do my thing ,不会被子进程的[%d]execl函数影响\n",getpid(),pid);
  return 0;
}

【Linux】进程控制(exec函数族)的理解和使用


请问:发生了子进程的程序替换,此时:父子进程的代码还是共享的码?

当然不会共享了,此时发生了写时拷贝,也就是会拷贝出一份代码和数据出来,然后子进程再被它的execl函数进行函数替换;


3. execl函数的使用

【Linux】进程控制(exec函数族)的理解和使用


4. execv函数的使用

execv和execl也是没啥区别,只不过execv叭execl的以列表形式的传参,变成了以数组形式的传参;


int main()
{
  if(fork() == 0){
 // execl("/usr/bin/ls","ls","-a","-l",NULL);
 	//等价下面的execv("/usr/bin/ls",argv); 
    char*const argv[] = {
      "ls",
      "-a",
      "-l",
      NULL 
    };
    execv("/usr/bin/ls",argv); 
    exit(1);
  }
  int waitRet = waitpid(-1,NULL,0); //阻塞等待所有子进程结束
  if(waitRet< 0){
    perror("wait error\n");
  }
  printf("parent wait child success\n");

  return 0;
}

【Linux】进程控制(exec函数族)的理解和使用


5. execlp函数的使用

execlp和execl的区别在于,execlp在第一个参数时候,不需要全路径,只需要写上执行命令的文件名即可,表示你需要执行谁,往后的参数也就是和execl的传参一样;


#include<stdio.h>
#include<unistd.h>//使用fork,exec函数
#include<sys/wait.h>//使用waitpid
#include<stdlib.h> //使用exit的头文件
int main()
{
  if(fork() == 0){
 // execl("/usr/bin/ls","ls","-a","-l",NULL);
    execlp("ls","ls","-a","-l",NULL); //等价上面的execl()
	//虽然这里的第一个参数和第二个参数都一样,但是含义不一样;
	//第一个参数表示iexeclp函数要执行命令的路径文件名,
	//第二个参数表示execlp在命令行上如何执行该命令
    exit(1);
  }
  int waitRet = waitpid(-1,NULL,0); //阻塞等待所有子进程结束
  if(waitRet< 0){
    perror("wait error\n");
  }
  printf("parent wait child success\n");

  return 0;
}

【Linux】进程控制(exec函数族)的理解和使用


6. execvp函数的使用

这个函数execvp和execv的区别在于。execvp第一个传参时候,不需要给出要执行命令的绝对路径,只需要给出要执行命令的文件名即可;


#include<stdio.h>
#include<unistd.h>//使用fork,exec函数
#include<sys/wait.h>//使用waitpid
#include<stdlib.h> //使用exit的头文件
int main()
{
  if(fork() == 0){
 // execl("/usr/bin/ls","ls","-a","-l",NULL);
    //execlp("ls","ls","-a","-l",NULL); //等价上面的execl()
    char* const argv[] = {
      "ls",
      "-a",
      "-l",
      NULL 
    };
    //execv("/usr/bin/ls",argv);
    execvp("ls",argv);//等价上面的execv()

    exit(1);
  }
  int waitRet = waitpid(-1,NULL,0); //阻塞等待所有子进程结束
  if(waitRet< 0){
    perror("wait error\n");
  }
  printf("parent wait child success\n");

  return 0;
}


【Linux】进程控制(exec函数族)的理解和使用


7. 验证exec函数族执行自己写的程序

  1. makefile 文件,编译链接生成myload和myexe两个文件;
  2. 这两个文件的作用是:myload加载myexe的程序,验证execv函数执行自己写的程序是否可以;
.PHONY:all
all:myload myexe # 该目标文件all不会被生成,是因为没有依赖方法

myload:myload.c
	gcc $^ -o $@
myexe:myexe.c
	gcc $^ -o $@

.PHONY:clean
clean:
	rm -rf myload myexe

myexe.c文件的内容:

#include<stdio.h>

int main(){
  printf("i am myexe\n");
  return 0;
}

myload.c文件

#include<stdio.h>
#include<unistd.h>//使用fork,exec函数
#include<sys/wait.h>//使用waitpid
#include<stdlib.h> //使用exit的头文件
int main()
{
  if(fork() == 0){
    execl("./myexe","./myexe",NULL);
    exit(1);
  }
  int waitRet = waitpid(-1,NULL,0); //阻塞等待所有子进程结束
  if(waitRet< 0){
    perror("wait error\n");
  }
  printf("parent wait child success\n");

  return 0;
}


测试结果:执行myoad,成功加载了myexe程序;
【Linux】进程控制(exec函数族)的理解和使用

8. execle 和 execve函数的使用

这个函数只是比execl多了一个e,表示最后一个参数需要给execle传入自定义的环境变量数组;
它的使用情况是:假如你要给一个你需要执行新的程序,加载一些自定义的环境变量给新的程序时候,你可以使用该函数;


测试:
myexe.c文件:打印环境变量的值,这个文件假如自己执行自己的话,那么就打印默认的环境变量;
假如其他文件使用execle传参给myexe.c环境变量,myexe.c就会执行该execle传过来的环境变量;


#include<stdio.h>

int main(){
  extern char** environ; //系统提供的环境变量指针,指向环境变量的指针数组
  int i = 0;
  for(;environ[i];i++){
    printf("%s\n",environ[i]);
  }
  return 0;
}


myload.c文件:使用execle函数,给该函数传递环境变量;使得myexe可执行程序可以获得该myload.c传递过去的环境变量;

#include<stdio.h>
#include<unistd.h>//使用fork,exec函数
#include<sys/wait.h>//使用waitpid
#include<stdlib.h> //使用exit的头文件
int main()
{
  if(fork() == 0){
    char* const env[] = {
      "MYENV0=123",
      "MYENV1=456",
      "MYENV2=789",
      NULL 
    };
     //char* const argv[] = {
    //	 	"./myexe",
   //  		NULL
    //};
    execle("./myexe","./myexe",NULL,env);
    //execlv("./myexe",argv,,env); //等价上execle的方式
    exit(1);
  }
  int waitRet = waitpid(-1,NULL,0); //阻塞等待所有子进程结束
  if(waitRet< 0){
    perror("wait error\n");
  }
  printf("parent wait child success\n");

  return 0;
}

测试结果:
【Linux】进程控制(exec函数族)的理解和使用文章来源地址https://www.toymoban.com/news/detail-437037.html


9. exec函数族使用的总结

  1. 有了exec函数族我们就可以用它来调用任何程序,也就是说,你还可以在C/C++,可以调用其他任何语言,比如python,Java等程序;
  2. 这些exec函数的接口函数本质是没有任何差别的,只是参数选项不同罢了;
  3. 为什么有那么多种接口,本质满足不同引用场景而已;
  4. 这些函数之间的调用关系,本质都会调用系统调用函数execve;
    【Linux】进程控制(exec函数族)的理解和使用

到了这里,关于【Linux】进程控制(exec函数族)的理解和使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…

    柴犬: 你好啊,屏幕前的大帅哥or大美女,和我一起享受美好的今天叭😃😃😃 1. 在调用fork函数之后, 当执行的程序代码转移到内核中的fork代码后 ,内核需要分配 新的内存块 和 内核数据结构 给子进程, 内核数据结构包括PCB、mm_struct和页表,然后构建起映射关系 ,同时

    2024年01月16日
    浏览(45)
  • Linux下进程及其进程地址空间以及一些进程的控制函数

    今天我们来分享一下Linux下的进程和进程地址空间以及一些进程的控制函数。 进程是操作系统分配资源的基本单位,一个进程是一个程序的一次执行过程。每启动一个进程,操作系统就会为它分配一块独立的内存空间,用于存储PCB、数据段、程序段等资源。每个进程占有一块

    2024年02月08日
    浏览(81)
  • Linux进程控制【进程程序替换】

    ✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Good judgment comes from experience, and a lot of that comes from bad judgment. 好的判断力来自经验,其中很多来自糟糕的判断力。 子进程 在被创建后,共享的是 父进程 的代码

    2024年01月17日
    浏览(36)
  • [Linux 进程控制(二)] 进程程序替换

    首先,我们要认识到,我们之前fork()所创建的子进程,执行的代码,都是父进程的一部分(用if-else分流或者执行同样的代码)! 如果我们想让子进程执行新的程序呢? 执行全新的代码和访问全新的数据,不再和父进程有瓜葛,这种技术就叫做程序替换 ,下面我们就来学习一

    2024年03月14日
    浏览(40)
  • Linux--进程控制(2)--进程的程序替换(夺舍)

    目录 进程的程序替换 0.相关函数 1.先看现象  2.解释原理 3.将代码改成多进程版  4.使用其它的替换函数,并且认识函数参数的含义 5.其它  关于进程替换我们需要了解的6个函数: 函数解释: 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。 如果调用出

    2024年04月29日
    浏览(25)
  • 【Linux】Linux进程控制及程序替换

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 在linux中fork是一个很重要的函数,它可以已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 fork函数返回两个值,一个是子进程的进程号(pid),另一个是0。 父进程可以通过pid来区分自己和子进程,子进程可

    2024年02月02日
    浏览(30)
  • 【Linux】进程控制 — 进程程序替换 + 实现简易shell

    上一节我们讲了进程终止和进程等待等一系列问题,并做了相应的验证,本章将继续对进程控制进行学习,我们将学习进程程序替换,进行相关验证,运用系统进程程序替换接口,自己模拟写一个shell,该shell能够实现执行指令,等一系列命令行操作…… 概念引入: 将可执行

    2024年02月06日
    浏览(38)
  • 【Linux】进程与可执行程序的关系&&fork创建子进程&&写实拷贝的理解

            系统会将此时在系统运行的进程的各种属性都以文件的形式给你保存在系统的proc目录下。 运行一个程序的时候,本质就是把磁盘中的程序拷贝到内存中,当一个进程运行起来的时候,它本质已经和磁盘中的可执行程序没有直接关系了。   当前我的myprocess程序正在运

    2024年03月19日
    浏览(31)
  • golang使用os/exec库查询进程

    本文主要介绍如何使用os/exec库查询进程。 输出: 上述代码逻辑会获取到当前系统中所有运行的进程,但如果只需要获取制定进程信息呢,就需要针对进程进行过滤。 第一种方式: 输出: 第二种方式: 输出:

    2024年02月11日
    浏览(26)
  • 【Linux】进程等待和替换——进程等待的原理、wait/waitpid方法、进程程序替换、进程替换原理、替换函数

    1.1进程等待的概念    进程等待指的是父进程等待子进程退出,以获取子进程的退出返回值,并释放子进程占用的资源。    当子进程先于父进程退出,但父进程没有关注子进程的退出状态时, 子进程会为了保存自己的退出状态而保持资源占用, 这种情况被称为“僵尸进

    2024年02月04日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包