• Linux11 --- 进程替换exec系列


    一、进程替换exec系列

    1、进程创建的原理(Linux上的):

    1)像区别于fork 复制进程(Linux上的):

    在这里插入图片描述

    2)进程创建的原理(Linux上的):

    当你在一个终端内,运行一个进程的时候,你会发现,如下:
    例如图所示,ps -f 进程创建的父进程为bash,并且每次创建进程的pid都不相同,但其父进程都是bash,pid这里都为2690;
    在这里插入图片描述
    注意:不同终端,bash的pid不同;
    在这里插入图片描述
    可见每当打开一个终端,都会有一个bash一直在;

    那么可以理解为:
    当一个终端创建,都会有一个pid固定的bash创建,
    如果要产生一个进程,先将其PCB复制,再将PCB内的pid+1,进程内容进行写时拷贝,在通过exec(简单可理解为替换)将所需创建进程的内容写入
    在这里插入图片描述
    另外:
    在这里插入图片描述
    在这里插入图片描述
    大多数的linux用的都说bash

    bash:命令解释器

    2、execl系列

    1)man execl:

    可见其为一个系列的函数
    在这里插入图片描述

    2)execl系列

    man execl看帮助手册

    //path:新替换的程序的路径名称
    //arg :传给新程序主函数的第一个参数,一般为程序的名字,
    /*(后面的...意思为)
    arg 后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数,
    (例如可变参数的函数使最多的:printf)
    */
    
    int execl(const char* path, const char * arg,...);
    int execlp(const char* file, const char * arg,...);//在环境变量PATH
    指定的路径里面搜索;
    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 * path, char* const argv[],char* const
    envp[]); //系统调用
    //前五个是库函数,最后一个是系统调用。所以本质上,上面5个都是通过第六个系统调用实现.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    可变参数的函数使用较多的:printf

    3)exec系列的使用示例(替换ps的使用)

    exec系列的使用方法的举例如下:

    先which ps(查看ps文件位置),获取其位置

    ps的位置:/usr/bin/ps
    在这里插入图片描述

    代码
    #include 
    #include 
    #include 
     
    int main(int argc,char *argv[],char *envp[])
    {
    	printf("main pid=%d\n",getpid());
    	
    	//execl("/usr/bin/ps","ps","-f",(char *)0);//只是ps也行,这里为替换ps -f 命令
    	//execlp("ps","ps","-f",(char *)0);
    	//execle("/usr/bin/ps","ps","-f",(char *)0,envp);
    	
    	char *myargv[]={"ps","-f",0};
    	// execv("/usr/bin/ps",myargv);
    	// execvp("ps",myargv);
    	execve("/usr/bin/ps",myargv,envp);
    
       //如果前面的替换实现成功,就不会运行后面的代码,表现为不会运行printf
    	printf("execvp error\n");
    	exit(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    注意,运行./test 后的pid为2930;
    ---------运行ps -f 的pid为2932。
    所以,替换实现。

    在这里插入图片描述

    my_execl

    #include 
    #include 
    #include 
    
    int main()
    {
        printf("mian pid=%d\n",getpid());
        execl("/usr/bin/ps","ps","-f",(char *)0);
    
        printf("execl error\n");
        exit(0);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    3、fork+exec()例子1

    fork+exec()是Linux上创建新进程的方式;

    例1:当前主程序复制产生一个子进程,子进程用程序ps替换自身;

    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
        printf("main pid=%d,ppid=%d\n",getpid(),getppid());
    
        pid_t pid=fork();
        assert(pid != -1);
        if(pid == 0)
        {
            printf("child pid = %d,ppid = %d\n",getpid(),getppid());
            
            execl("/usr/bin/ps","ps","-f",NULL);
    
            printf("execl error\n");
            exit(0);
        }
        wait(NULL);
        exit(0);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    例2:当前主程序复制产生一个子进程,子进程用新程序"b"替换自身;

    //main.c
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    int main(int argc,char *argv[],char *envp[])
    {
    	printf("main pid=%d\n",getpid());
    	pid_t pid=fork();
    	assert(pid!=-1);
    	if(pid==0)
    	{
    		char *myargv[]={"b","hello","abc","123",(char *)0};
    		execve("./b",myargv,envp);
    		perror("execve error");
    		exit(0);
    	}
    	wait(NULL);
    	printf("main over!\n");
    	exit(0);
    }
    //b.c
    #include 
    #include 
    #include 
    #include 
    #include 
    int main(int argc,char *argv[],char *envp[])
    {
    	printf("b pid=%d\n",getpid());
    	int i=0;
    	printf("argc=%d\n",argc);
    	for(;i<argc;i++)
    	{
    		printf("argv[%d]=%s\n",i,argv[i]);
    	}
    	for(i=0;envp[i]!=NULL;i++)
    	{
    		printf("envp[%d]=%s\n",i,envp[i]);
    	}
    exit(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    第1章:React 入门
    MySQL数据库的回滚rollback是怎么做到的?
    【Swift 60秒】39 - Returning values
    poshmark前景,怎么快速提升销量!
    6G物理层安全技术综述
    年度盘点,四年的精华合集「GitHub 热点速览」
    [贪心]Black Magic 2022杭电多校第7场 1004
    armv8单独编译Qt的串口模块
    前端HTML相关知识
    phpword 导出图表格式不兼容问题
  • 原文地址:https://blog.csdn.net/kyrie_sakura/article/details/127307714