• 【linux进程(五)】进程间切换以及环境变量问题


    💓博主CSDN主页:杭电码农-NEO💓

    ⏩专栏分类:Linux从入门到精通

    🚚代码仓库:NEO的学习日记🚚

    🌹关注我🫵带你学更多操作系统知识
      🔝🔝


    在这里插入图片描述


    1. 前言

    掌握了前面文章中
    Linux进程相关的内容后,
    本篇文章将进行一些实践
    包括自制计算器,自己写bash指令等

    本章重点:

    本篇文章着重讲解Linux是怎样进行
    进程间切换的,并且拓展内核2.6版本
    的进程运行实例.紧接着讲解main函数
    的两个参数以及含义后,自我实现一个
    计算器和touch指令,最后讲解环境变量
    的基本概念和查看方式!


    2. 进程间切换

    我们知道一个事实,CPU在调度进程时
    并不是一个进程一直在占用CPU资源
    它过段时间会被取下来放入其他进程
    所以这中间肯定存在进程切换这一过程

    两个问题:

    1. 没运行完的进程数据后来去哪儿了?
    2. 当一个进程被取下时
      它在CPU的数据是否会被删除?

    第一个问题

    很明显,当一个进程在没运行完的
    情况下被取下时,肯定会保存一个
    信息,那就是当前进程运行到哪儿了?
    和C语言的代码相似,当前代码运行
    到哪儿了系统是怎么知道的?请看下图:

    在这里插入图片描述所以其实在进程运行时,是会使用到
    这些寄存器的!进程产生的各种数据
    会在寄存器中进行临时保存!

    进程在切换时会不断对自己的数据
    进行保存(被取下时)和恢复(重新运行时)
    当进程进行保存时是保存寄存器中的数据
    而不是寄存器本身,并且这些数据会被保存
    至一个进程的PCB当中!
    
    • 1
    • 2
    • 3
    • 4
    • 5

    第二个问题:

    事实上,一个进程被取下来时
    CPU并不会删除它的临时数据
    而是当下一个进程被放入时,用
    下一个进程的数据将上一个进程
    的数据覆盖了!


    3. Linux2.6内核进程调度队列

    注意,这部分是选学,有余力的同学可以看看

    请看下图(着重看红框和篮框)
    在这里插入图片描述
    我们着重讲解活跃进程和过期进程的交互!


    3.1 活跃进程

    首先知道一个事实,Linux中的进程
    优先级范围是60~99总共40个等级
    其次,运行队列中分活跃进程组和
    过期进程组,这个后面再说它们的功能
    先来看活跃进程的queue:
    在这里插入图片描述

    CPU在运行时会从上到下扫描队列
    若此位置不为空就去运行它指向的PCB
    若为空就往后走找优先级最高的进程!


    3.2 过期进程

    现在有一个问题:当一个优先级为90的
    进程正在运行,但是此时突然多了一个优
    先级为80的进程,那么这个多加入的进程也
    是放入活跃队列中和其中的进程抢占资源吗?

    事实上并不会,因为如果有很多优先级很高
    的进程不断加入进来,内些原本优先级比较
    低的进会迟迟得不到CPU的资源,会进程饥饿!
    所以新加入进来的进程会被放进过期队列中!
    和活跃进程一样也是按照优先级排列!

    它的原理请看下图:

    在这里插入图片描述
    那么当活跃队列中的进程被调度完了
    此时CPU是去过期进程调度吗?

    答案是不!系统直接使用swap()函数
    将活跃进程和过期进程的内容交换
    CPU还是在处理活跃队列的进程!


    4. main函数参数–命令行参数

    main函数其实是有参数的,本篇文章
    我只介绍main函数的两个参数

    int main(int argc , char* argv[]);
    这两个参数又被称为命令行参数
    argv是一个数组,指向的元素类型是char*
    也就是说argv是一个字符串数组
    argc代表这个数组的元素个数!
    
    • 1
    • 2
    • 3
    • 4
    • 5

    现在我们并不知道这个数组中
    存放的是什么字符串,但是可以写个
    代码验证一下,既然知道数组名和元素个数
    那么我们就可以通过打印的方式来查看

    #include      
    int main(int argc,char* argv[])    
    {    
        int i=0;                                                                                                                                                            
        for(i=0;i<argc;i++)    
        {    
            printf("%d: %s\n",i,argv[i]);    
        }    
        return 0;    
    }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过下面的视频观察现象:

    main


    可以发现一个问题:

    当我们运行可执行程序a.out时
    它会打印0: ./a.out.当我们以空格
    为分割在./a.out后面继续输入字符串时
    并且输入的是随机字符串,它会以空格
    为分割,分别打印出数组中下标为0,1,2
    的字符串,这些输出的字符串正是我们输入的!

    看下图得出结论:

    在这里插入图片描述

    注:将命令行输入的字符串放入argv数组是OS干的!


    5. 利用main函数参数实现简易计算器

    既然main函数参数可以读到命令行
    中输入的字符串,所以可以用代码实现
    一个简易的计算器,代码如下:

    #include    
    #include    
    #include    
    int main(int argc,char* argv[])    
    {    
        if(argc!=4)    
        {    
            printf("%s OP[add|sub|mul|div] d1 d2\n",argv[0]);    
            return 1;    
        }    
        int x=atoi(argv[2]);    
        int y=atoi(argv[3]);    
        if(strcmp(argv[1],"add")==0)    
            printf("%d + %d = %d\n",x,y,x+y);    
        else if(strcmp(argv[1],"sub")==0)    
            printf("%d - %d = %d\n",x,y,x-y);    
        else if(strcmp(argv[1],"mul")==0)    
            printf("%d * %d = %d\n",x,y,x*y);    
        else if(strcmp(argv[1],"div")==0)                                                                                                                                   
            printf("%d / %d = %d\n",x,y,x/y);    
        else    
            printf("输入操作符错误");    
        return 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

    使用方法:

    1. 用户必须先输入可执行程序:a.out
    2. 第二个字符串输入加减乘除其中一个
    3. 第三,第四个字符串输入操作数
    4. 若其中有一个环节输入错误会报提醒

    在这里插入图片描述


    6. 模拟实现Linux中的bash指令

    当模拟实现了计算器后,我们隐约可以
    发现,其实Linux下的指令如ls,pwd或touch
    其实就是调用了不同的可执行程序来完成的!

    比如touch指令,输入touch和要创建的文件名
    本质就是在C语言程序中创建一个和输入的
    文件名一样的文件来间接创建文件

    mytouch代码如下:

    #include    
    int main(int argc,char* argv[])    
    {    
        if(argc != 2)//输入的字符串不规范    
        {    
            printf("touch missing file operand\n");    
            return 1;    
        }    
        FILE* fp = fopen(argv[1],"w");                                                                                                                                      
        if(fp!=NULL)    
            fclose(fp);    
        return 0;    
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    现在我们在Linux下输入指令创建文件:

    在这里插入图片描述

    如果有需要,我们可以自己写一份
    可执行程序来模拟Linux下所有的指令!


    7. 环境变量PATH初认识

    上面所说的内容你可能能理解
    就是利用了main函数的参数进行各种运用

    但是有几个问题需要解决:

    • 为什么我们自己写的程序运行时要加./
    • 但是系统中的指令:ls,pwd等不用加./?
    • 我们自己写的指令能不能不加./?

    我们说执行一个程序的前提是要
    找到此程序,我们自己写的程序要
    加上./的本质就是让操作系统在当前
    目录下寻找我们写的程序,那么为什么
    系统中的程序不用加./就能找到呢?

    这不得不引出一个概念: 环境变量
    保存程序的默认搜索路径的环境变量
    叫做: PATH

    在运行程序时,系统会去PATH中
    找当前可执行程序在不在这些路径中
    如果在就直接执行程序,不在就报错

    查看环境变量PATH:

    使用指令: echo $PATH

    在这里插入图片描述

    这些路径以冒号:为分割

    因为我们自己写的程序不在这些路径中
    所以我们需要加上./来运行程序!


    8. 修改环境变量PATH

    要想我们的指令像系统指令一样运行
    我们可以将自己写的程序的路径加入
    到环境变量PATH中!

    使用指令: PATH = $PATH:要添加的路径

    在这里插入图片描述

    此时我已经将我的路径添加到PATH了
    现在我直接像系统指令一样运行我的指令:

    在这里插入图片描述

    请注意,当你将你的路径添加后
    下次重启时又会恢复为默认路径
    所以想一劳永逸的话可以将你自己
    的可执行程序放入默认的路径中!


    9. 总结

    进程的学习需要理论和实践相结合
    本篇文章主要是实践部分,而然有两个
    问题剖给大家:main函数就只有两个参数吗?
    环境变量到底有什么用处?


  • 相关阅读:
    【STM32教程】第二章 通用输入输出口GPIO
    故障:不能打开 Office 应用程序,并指示有账户正在登录
    被时代逐渐舍弃的FTP,怎么找到替代传输方案呢?
    同步时序逻辑电路
    【Vue】同一个页面多次复用同一个组件数据相互干扰问题
    异地恋挺痛苦的
    二、准备开发与调试环境
    SpringBoot-打印请求的入参和出参
    [攻防世界 XCTF 4th-WHCTF-2017] BABYRE
    Java项目:基于ssh的酒窖酒水管理系统
  • 原文地址:https://blog.csdn.net/m0_61982936/article/details/133828693