Linux进程(2)
上篇,我们已经了解了关于进程的一部分知识了,那么我们现在继续来学习进程。
上篇,我们已经了解了并发的概念,现在我们来进一步理解它:
一、并发的定义
多个进程在一个CPU下通过进程切换的方式,在一段时间内让多个进程都得以推进,称为并发。
进程切换基于时间片轮转的调度算法,通过时间片来控制进程在CPU上的执行时长。
二、进程上下文与CPU寄存器的关系
我们来想想:为什么函数返回值,会被外部拿到呢?
实质上它是通过CPU寄存器
eg:
return a -> mov eax 10
- 通用寄存器:如 eax 、 ebx 、 ecx 、 edx 等
- 栈帧相关寄存器: ebp (基址指针)、 esp (栈指针)。
- 状态寄存器:如 status ,记录进程的运行状态。
- 程序计数器(eip/pc):记录当前进程正在执行指令的下一行指令的地址,系统通过它得知进程当前执行到哪行代码。
寄存器很多,它们扮演的是什么角色?
这些寄存器的作用是将高频数据放入其中以提高效率,
怎么提高效率?
因为它们保存的是与进程相关的数据,可被进程访问或修改。
因此,我们得出来结论:
CPU寄存器中保存的是进程的临时数据(即进程的上下文)
三、进程切换时的上下文操作
进程在从CPU上离开(被切换)时,需要:
1. 保存上下文:将CPU寄存器中自己的上下文数据保存好(比如存入 task_struct 结构体的 struct reg_info 中,该结构体包含 eax 、 ebc 、 eip 等寄存器信息)。
2. 恢复上下文:后续再次获得CPU执行权时,恢复之前保存的上下文数据,从而继续执行。
保存上下文的目的是为了未来能恢复进程的执行状态。
环境变量:
我们接下来以下面的流程讲解环境变量:
见见环境变量?
什么是环境变量?
环境变量的原理是什么?
环境变量有什么作用?
什么是环境变量:
环境变量是操作系统中用来指定操作系统运行环境的一些参数
eg:我们C/C++中链接的时候,并不知道动静态库的在哪,而程序一样可以运行,这就是环境变量提供的帮助。
环境变量是系统提供的一组name=value形式变量,不同的环境变量,有不同的用户,而且它通常具有全局属性。
见见环境变量
PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。
USER:当前主机的用户
查看环境变量:
echo $NAME //NAME:你的环境变量名称
区别平时指令与可执行程序:
对比./test执行和之间test执行
我们发现我们自己写的程序得./test才能打印出来内容,test不能打印出来内容。
那么,又会有疑惑了, 为什么有些指令(eg:ls,ll,pwd等等)可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行?
这就与我们的环境变量有关:
现在将我们的程序所在路径加入环境变量PATH当中, export PATH=$PATH:test程序所在路径。
ps:如果不确定的话,可以采用pwd,查看你当前所在的绝对路径!!
观察root与用户之间的HOME差异:
其中:两者之间cd ~也是不一样的。这也是环境变量的差异形成的。
常见的环境变量的指令:
1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量
环境变量在内核当中的管理方式:
也是有一直环境变量表,里面存的就是各个路径。
每个程序都会收到一张环境变量表,那么,存在多个程序的话,一定会存在多张环境变量表,那么多张表,我们要不要管理起来?肯定要,怎么管理呀?
这就用到了我们上篇说到的:先描述,再组织(这个思想我们经常会使用)
通过代码获取环境变量:
yum install -y links
是一款文本模式的网页浏览器,可以在没有图形界面的终端环境中浏览网页
首先,我们得补充的点是,main函数也是有参数的,
int main(int argc, char *argv[], char *env[])
第一个是命令行参数个数
第二个是字符串函数指针数组,存储的是每个命令行参数的具体内容,
第三个是环境变量表。
现在我们来看看argv[]里面:
通过上面的打印内容,我们可以知道,我们平常输入的指令:ls -l -a
底层也是通过argv来传的,后面我们再来模拟实现。
我们来看一下关于环境变量表:
通过内部来获取:
通过外部来获取
执行打印出来的是环境变量表的内容。
ps:libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
通过系统调用获取或设置环境变量
getenv/putenv(设置或修改环境变量的函数:到实现Shell的时候再用)
证明环境变量是具有全局属性:
环境变量里没有,而当我们添加进去后:
说明:环境变量是可以被子进程继承下去的。
- 我们运行的进程都是bash的子进程,bash启动时会从系统配置文件(如 /etc/profile 、 ~/.bashrc )读取环境变量,子进程会继承父进程(bash)的环境变量。
- 验证方法:可在bash中设置环境变量后,启动一个子进程(如运行C程序),在程序中打印 env[] 或用 getenv() 查看,确认变量是否被继承。
我们来认识一下两批命令:
1.常规命令:通过创建子进程完成的
- 文件操作类: ls (列出文件)、 cp (复制文件)、 mv (移动/重命名文件)、 rm (删除文件)、 find (查找文件)、 grep (文本搜索)。
- 系统信息类: top (查看进程资源)、 ps (查看进程)、 df (查看磁盘空间)、 free (查看内存)、 uname (查看系统信息)。
- 网络工具类: ping (网络连通性测试)、 curl (HTTP请求)、 wget (下载文件)、 ifconfig (查看网络接口)。
- 编程工具类: gcc (编译C程序)、 python (执行Python脚本)、 java (运行Java程序)。
- 包管理类: yum (RHEL/CentOS包管理)、 apt (Debian/Ubuntu包管理)、 pip (Python包管理)。
2.内键命令:bash不创建子进程,而是由自己亲自执行,类似于bash调用了自己写的或者系统提供的函数。
环境变量与Shell配置类: export (设置环境变量)、 unset (删除变量)、 source (加载配置文件)、 alias (设置命令别名)。
- 目录操作类: cd (切换目录)、 pwd (显示当前路径)。
- Shell控制类: exit (退出Shell)、 exec (替换当前Shell进程)、 set (设置Shell选项)、 shopt (调整Shell行为)。
- 流程控制类: if 、 for 、 while 、 case (Shell脚本中的流程控制结构)、 alias (定义命令别名)。
- 其他常用类: echo (输出内容)、 test (条件测试)、 type (判断命令类型)、 read (读取用户输入)。
进程地址空间
什么是进程地址空间呢?
如果你是第一次学Linux的话,肯定是蒙的,但是,如果你在C/C++学习过程中有没有听说过栈,堆,常量区等等,这些知识就是在地址空间里面,只不过它们只是用户层面上,而我们在Linux当中还需要更详细的学习里面的细节。包括内核区,用户区。
下面是学习Linux中常见的一张表:(网上找的)我们未来会围绕下面表的内容,进行逐一讲解分析。拆分讲解。
虚拟地址的引入:
我们会发现:不同进程,它们的地址怎么是一样的??按照正常来说:是不可能同一个变量,同一个地址,同时读取,读到不同的内容??
因此:如果变量的地址,是物理地址,那么不可能存在上面的现象!所有它不可能是物理地址,而是虚拟地址!!!!
我们写C/C++代码的全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理
怎么做到使用虚拟地址来找到对应物理地址呢?
这就得用到页表这个结构了。
现在,就列出一个框架出来,后面一点一点地完善它!
好了,本次就先分享到这里,希望大家一起进步!!!
最后,到了本次鸡汤环节:
每天愉悦地进步一点点!