Linux进程控制(进程替换)

news2024/11/16 18:38:50

目录

一、进程程序替换原理

 二、进程替换函数

三、函数实现子进程进程替换

3.1 测试函数

3.2 写时拷贝保证替换后的进程独立性

四、自我实现一个简单的 shell

五、内置命令

5.1 pwd查询路径本质

5.2 内置命令概念

5.3 自我实现shell Pro


 先见见进程替换:

#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("the process is running...\n");
    execl("/usr/bin/ls","ls","--color=auto",NULL);//进程替换
}


一、进程程序替换原理

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变!


 二、进程替换函数


系统调用接口:

函数封装接口:

#include <unistd.h>`
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[]);

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

可变参数:

 我们发现每个函数参数表中都有...,这代表着我们的参数列表是可变参数列表!

可变参数列表允许参数个数是动态的,想传多少就传多少,最后以NULL结尾!我们原来用的printf函数也是典型的可变参数!


三、函数实现子进程进程替换

3.1 测试函数

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
    pid_t id=fork();
    if(id==0)
    {
        printf("the child process is running...\n");
        printf("我是子进程,id=%d\n",getpid());
        sleep(1);
        //法一:execl 列表传命令
        //execl("/usr/bin/ls","ls","--color=auto",NULL);//系统命令
        //execl("./mybin","mybin",NULL);//自己编写的程序

        //法二:execlp 环境变量PATH
        //execlp("ls","ls","--color=auto",NULL);

        //法三:execv 数组传命令
        //  char* const _argv[]={
        //     "ls",
        //     "-a",
        //     "-l",
        //     "--color=auto",
        //     NULL
        // };
        //execv("/usr/bin/ls",_argv);

        //法四:execvp 二和三的组合
        //  char* const _argv[]={
        //     "ls",
        //     "-a",
        //     "-l",
        //     "--color=auto",
        //     NULL
        // };
        // execvp("ls",_argv);

        //法五:execle 获取环境变量
        extern char**environ;
        char* const _envp[]={
            "myval=666",
            NULL
        };
        putenv("myval=666");//自己设置环境变量
        execle("./mybin","mybin",NULL,environ);
        exit(-1);//进程替换失败
    }
    else if(id>0)
    {
        int status=0;
        pid_t ret=waitpid(id,&status,0);
        sleep(3);
        if(ret>0)
        printf("wait success:%d  sig code=%d  child exit code=%d\n",ret,status&0X7F,(status>>8)&0XFFFF);
    }
    else
    {
        printf("creat child process error!\n");
    }
    return 0;
}

法四结果:


法五结果:


3.2 写时拷贝保证替换后的进程独立性

💡💡

子进程程序替换前共享父进程代码!程序替换会将磁盘代码替换原代码!进程具有独立性,子进程不能直接替换共享代码而影响父进程!所以操作系统会对子进程代码进行写时拷贝!


四、自我实现一个简单的 shell

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<assert.h>
#include<string.h>
#define NUM_SIEZ 1024
char Command_Line[NUM_SIEZ];
#define OPT_NUM 64
char* myargv[OPT_NUM];
#define DEBUG
int main()
{
while(1)
{
    printf("[用户名@主机名  当前路径]$ ");
    fflush(stdout);//刷新缓冲区
    char* str=fgets(Command_Line,sizeof(Command_Line)-1,stdin);//从标准输入获取字符串
    assert(str!=NULL);
    //"abcde\n" 让最后一个字符为NULL(0)!为后面命令数组结尾获取0!
    Command_Line[strlen(Command_Line)-1]=0;
#ifdef DEBUG
    //以空格为分隔单位,获取命令与命令选项!
    myargv[0]=strtok(Command_Line," ");
    int i=1;
    while(myargv[i++]=strtok(NULL," "));
#endif
    //创建子进程
    pid_t id=fork();
    if(id==0)//子进程程序替换
    {
        execvp(myargv[0],myargv);
        exit(1);//进程替换失败
    }
    else if(id>0)//父进程等待
    {
        waitpid(id,NULL,0);
    }
    else
    {
        printf("creat child process error!\n");
    }
}      
    return 0;
}


五、内置命令

问题引入:下面我们来看一看自我实现的shell 实现下面的命令:

 


5.1 pwd查询路径本质


 进程路径是可以被修改的,磁盘路径是亘古不变的!,pwd的本质是查询当前进程的工作目录!我们可以通过chdir修改工作路径!


 5.2 内置命令概念

内置命令指的是命令由父进程本身执行,不靠子进程程序替换的命令!例如 echo pwd 命令!


5.3 自我实现shell Pro

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<assert.h>
#include<string.h>
#define NUM_SIEZ 1024
char Command_Line[NUM_SIEZ];
#define OPT_NUM 64
char* myargv[OPT_NUM];
//子进程返回结果
int last_sigcode=0;
int last_exit_code=0;
int main()
{
while(1)
{
    printf("[用户名@主机名  当前路径]$ ");
    fflush(stdout);
    char* str=fgets(Command_Line,sizeof(Command_Line)-1,stdin);//从标准输入获取字符串
    assert(str!=NULL);
    //"abcde\n" 让最后一个字符为NULL(0)!为后面命令数组结尾获取0!
    Command_Line[strlen(Command_Line)-1]=0;

    //以空格为分隔单位,获取命令与命令选项!
    myargv[0]=strtok(Command_Line," ");
    int i=1;
    //文件带上标识颜色
    if(strcmp(myargv[0],"ls")==0)
    {
        myargv[i++]="--color=auto";
    }
    
    while(myargv[i++]=strtok(NULL," "));
    if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"cd")==0)
    {
        chdir(myargv[1]);//改变父进程程序路径
        continue;//内置命令,直接结束
    }
    if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"echo")==0)
    {
        if(strcmp(myargv[1],"$?")==0)//获取上一次进程结果
        {
            printf("sigcode=%d exit_code=%d\n",last_sigcode,last_exit_code);
            continue;
        }
        else
        {
            printf("%s\n",myargv[1]);
            last_exit_code=0;
            last_sigcode=0;
            continue;
        }
    }
    //创建子进程
    pid_t id=fork();
    if(id==0)
    {
        execvp(myargv[0],myargv);
        exit(1);//进程替换失败
    }
    else if(id>0)
    {
        int status=0;
        int ret=waitpid(id,&status,0);
        assert(ret>0);
        last_sigcode=status&0X7F;
        last_exit_code=(status>>8)&0XFF;
    }
    else
    {
        printf("creat child process error!\n");
    }
}      
    return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity学习笔记--如何在Unity中把自己的代码打包成dll给别人使用?(纯保姆式教学,看完还不会,今晚八点,来沙城砍我)

目录前言背景步骤一步骤二步骤三步骤四&#xff08;关键&#xff01;&#xff01;&#xff01;&#xff09;步骤五步骤六步骤七步骤八步骤九步骤十总结前言 最近公司放年假了&#xff0c;没什么事做&#xff0c;所以来公司学习&#xff08;蹭吃蹭喝ing&#xff09; 突然记起来…

CSS总结笔记+案例

此文章属于前端篇中的第二节CSS样式 继前期HTML标记语言 CSS总结笔记&#xff1a; 3.CSS样式 css&#xff0c;专门用来“美化”标签。 基础CSS&#xff0c;写简单页面&看懂&改。模块、调整和修改 3.1CSS应用方法 1.在标签上 - 高度和宽度样式&#xff1a; <i…

linux基本功系列之alias命令实战

本文目录 文章目录前言&#x1f680;&#x1f680;&#x1f680;一. alias命令介绍二. 语法格式及常用选项三. 参考案例3.1 查看系统已经存在的别名3.2 设置别名的操作3.3 取消别名3.4 alias的全局生效和当前用户生效四. 使用命令的注意事项总结前言&#x1f680;&#x1f680;…

行云洞见 | 为什么说云端IDE代表未来趋势?

原文作者&#xff1a;行云创新解决方案架构师 李楠 预知未来最可靠的方法是了解历史&#xff0c;让我们简单回顾下IDE的发展史。 所谓IDE&#xff0c;即集成开发环境&#xff0c;是软件开发人员在他们用于编程的计算机本地安装的应用程序。伴随着计算机编程语言从第一代机器语…

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(万用表)】

目录 序言 &#x1f34d;放置虚拟仪器仪表 &#x1f349;万用表 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI Multisim 14.0&#xff0c;打开如图所示的启动界面&#x…

【虹科分享】虹科ATEasy软件,您的测试执行和开发专家!

测试和执行专家 虹科ATEasy是功能测试&#xff0c;自动测试系统&#xff0c;数据采集&#xff0c;过程控制和仪表系统的测试执行和快速应用开发框架。虹科ATEasy提供开发&#xff0c;部署和维护软件组件的所有必要工具&#xff0c;包括仪器驱动程序&#xff0c;测试程序&#x…

SGA与PGA的区别

前几天有被别人问到什么是SGA和PGA&#xff0c;说实在的&#xff0c;之前一直搞分布式&#xff0c;已经基本把单机里面的这两个概念忘记的差不多了&#xff0c;不过当时还是根据自己的一点数据库经验说了点七七八八&#xff0c;后来网上查了一下相关说明&#xff0c;发现自己的…

现货黄金与白银现货的区别

黄金与白银同为贵金属&#xff0c;二者均在人类货币史上担当过货币的功能&#xff0c;而现货黄金与白银现货作为其最重要的金融衍生品&#xff0c;都具备良好的收益性、流动性和的可操作性&#xff0c;都是比较理想的投资产品。那么和现货黄金和白银现货的区别在哪里呢?小编认…

C++初学者学习笔记

面向对象的程序设计 初步理解 相比较于面向过程的程序设计来说有更多的封装的函数可以使用&#xff0c;相比较来说会比较方便。但是如何去设计整个程序的思路也是需要一定的训练的。 C 简介 C 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言&#xf…

linux系统目录结构

在 Linux 或 Unix 操作系统中&#xff0c;所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构。 文件系统的最顶层是由根目录开始的&#xff0c;系统使用 / 来表示根目录。在根目录之下的既可以是目录&#xff0c;也可以是文件&#xff0c;而每一个目录中又可以包含…

【荐书】C程序设计语言(第二版)

“在大多数人眼中&#xff0c;我是个一事无成、乖僻古怪、令人作呕的人。我毫无社会地位可言&#xff0c;也永远不会有。总之&#xff0c;我是底层人中的底层人。好吧&#xff0c;就算这些看法都完全正确&#xff0c;我也想有那么一天&#xff0c;通过我的作品向他们展示&#…

C++模板(函数模板,类模板)的基本使用与非类型模板参数与模板的特化

C模板模板初阶泛型编程函数模板函数模板概念函数模板格式函数模板的原理函数模板的实例化隐式实例化显式实例化&#xff1a;在函数名后的<>中指定模板参数的实际类型模板参数的匹配原则类模板类模板的定义格式类模板的实例化模板进阶非类型模板参数模板的特化概念函数模板…

【TypeScript】TS与Vue

TypeScript与Vue 文章目录TypeScript与VuedefineProps与TypescriptdefineEmits与Typescriptref与Typescriptreactive与Typescriptcomputed与Typescript事件处理与TypescriptTemplate Ref与Typescript可选链操作符非空断言参考链接&#xff1a;https://vuejs.org/guide/typescri…

【OpenGL学习】texture

纹理 一、什么是纹理&#xff1f; 引用百度百科的定义&#xff1a; 计算机图形学中的纹理既包括通常意义上物体表面的纹理即使物体表面呈现凹凸不平的沟纹&#xff0c;同时也包括在物体的光滑表面上的彩色图案&#xff0c;通常我们更多地称之为花纹。对于花纹而言&#xff0c…

ES6 课程概述⑦

文章目录Vuex_State安装使用State在 Vue 组件中获得 Vuex 状态mapState 辅助函数Vuex_Getter通过属性访问通过方法访问mapGetters 辅助函数Vuex_Mutation在组件中提交 Mutation提交载荷&#xff08;Payload&#xff09;对象风格的提交方式使用常量替代 Mutation 事件类型Mutati…

Spring Boot(五十六):基于Redis的搜索栏热搜功能

1 功能要求 使用SpringBoot和redis实现一个简单的热搜功能&#xff0c;具备以下功能&#xff1a; 搜索栏展示当前登陆的个人用户的搜索历史记录&#xff0c;删除个人历史记录用户在搜索栏输入某字符&#xff0c;则将该字符记录下来 以zset格式存储的redis中&#xff0c;记录该…

Flink DataSet API和DataStream API 对于WordCount的演示

文章目录准备工作Flink DataSet APIFlink DataStream API结论准备工作 pom依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-insta…

如何多人配音一个作品?这3招帮你快速实现

大家平时喜欢听书吗&#xff1f;听书是一种既能释放双眼&#xff0c;又能降低压力的放松方式。那么大家平时在听书的时候&#xff0c;有没有碰到过一些多人配音的小说&#xff1f;大家有好奇过这样的小说是怎么来的吗&#xff1f;今天&#xff0c;教大家多人配音怎么制作的&…

请问想考软考,零基础的话,哪个证书最好考呢

可以直接考中级&#xff0c;软考中级中也有适合零基础报考的&#xff0c;中级的含金量也比初级的高&#xff0c;初级的用途不太大&#xff0c;建议直接中级。 系统集成项目管理工程师&#xff0c;软考中级比较热门的一个科目&#xff0c;零基础的也适合相比较容易通过。 软考…

Fisher确切概率基本原理详解

Fisher确切概率 基本原理 比较两组有效率是否有差异。 在周边合计不变的情况下&#xff0c;计算实际频率变动时的Pi&#xff08;概率&#xff09;。然后计算累积概率&#xff0c;依据检验水平做推断。 累积概率的计算 以a从小到大的概率排序 左侧概率&#xff1a;现有样本…