0


Linux——进程(上)

一.冯·诺依曼体系结构

  • 数据在计算机的体系结构中流动进行加工处理,从一台设备到另一台设备,本质是一种拷贝
  • CPU不直接和外设打交道,CPU只和内存打交道。
  • 外设(输入输出设备)的数据,不是直接给CPU,而是要先放入内存中。

二.操作系统

操作系统是一款进行软硬件资源管理的软件

操作系统对下进行软硬件管理工作,对上层提供良好,稳定,高效的运行环境。

整个计算机的体系结构为层状结构,操作系统在其中起承上启下的作用。


三.进程

进程文件首先存在于磁盘中,当被调度时,会被加载进入内存,随后由操作系统先描述,创建进程PCB,再组织所有的进程成为一个链表,随后由CPU对进程链表进行管理

  • 进程=PCB➕自己的代码数据
  • 用户要使用操作系统,必须使用系统调用的方式。
  • 进程 = 内核task_struct结构体 + 程序的代码和数据。
  • PCB:进程控制块,进程属性的集合。

1.进程的tesk_struct内部属性

(1)启动

  • ./xxxx,本质就是让系统创建进程并运行。我们自己写的代码形成的可执行程序、可执行的系统命令都是可执行文件,在linux中运行的大部分指令操作,本质都是运行进程。
  • 每一个进程都要有自己的唯一标识符,叫做进程pid。
  • ctrl + C就是在用户层面终止进程,kill -9 pid可以直接杀掉进程。

2.如何查看进程信息

  • ps:查看当前系统中对应的进程。
  • axj:a表示all全部,xj表示详细信息。
  • grap XXXX:过滤出只有包含XXXX的信息。
  • grep -v grap:删除grep进程的信息。
  • head -x:显示信息的前x行。
  • ps axj | grap XXXX:查看XXXX进程的详细信息。
  • &&:指令级联符号,能够使多个指令同时进行。
  • while :; do 指令; sleep 1; done:每隔一秒钟执行一次该指令
  • while :; do ps ajx | head -1 && ps ajx | grep XXXX | grep -v grep; sleep 1; done:每隔1秒循环打印出XXXX进程的信息。

3.进程创建的代码方式

需要头文件:**#include<sys/types.h>,#include<unistd.h>**:

  • pid_t getpid(void):获得当前进程的进程id。
  • pid_t getppid(void):获得当前进程的父进程id。
  • pid_t fork(void):从已存在的进程中创建一个新进程,二者互为父子进程。fork函数的返回值有两个,成功创建子进程,则返回0给子进程,同时返回子进程的pid给父进程;创建失败返回 -1。

创建一个进程,本质是系统中多了一个进程,多了一个内核task_struct,有自己的代码和数据。

父进程的代码和数据从磁盘加载而来,子进程如果没有自己的代码和数据,则会默认继承父进程的代码和数据(子进程会继承父进程全部的代码,但是只会执行fork函数之后的所有代码)

进程具有独立性,父子进程任意一方被杀掉都不会影响另一方。

bash:命令行解释器,整个系统指令执行的父进程。

chdir(路径)函数:改变进程的执行路径。

进程的信息可以通过 **/proc **系统文件夹查看。


4.进程状态

  • R(running)状态:进程运行的状态。
  • S(sleeping)状态:进程在等待“资源”就绪,可以被中断的状态。
  • T(stopped)状态:让进程暂停,等待被进一步唤醒。
  • t(tracing stop)状态:被追踪而导致的进程暂停,如调试断点。
  • D(disk sleep)状态:不可被杀,深度睡眠状态,不可中断睡眠。
  • Z(zombie)状态:僵尸状态。
  • X(dead)状态:僵尸进程被释放后的状态。

kill -l指令:显示进程控制信号。


(1)僵尸进程

子进程比父进程先退出,还未被父进程回收,需要维持自己的退出信息,在自己的进程task_struct会记录自己的退出信息,未来让父进程来进行读取,此时的子进程为僵尸进程。如果没有父进程,僵尸进程会一直存在。

僵尸进程不能被kill掉。

僵尸进程不被关心的原因:直接在命令行中启动的进程,它的父进程是bash,bash会自动回收新进程的Z。


(2)孤儿进程

父进程比子进程先退出,子进程就会成为孤儿进程

孤儿进程一般都会被1号进程(OS本身)进行领养的,保证子进程的正常回收。

孤儿进程可以被kill掉。


(3)运行状态

并发:让多个进程在一个CPU内以时间片轮转调度算法等切换的方式进行调度,在一个时间段内得以同时推进代码。

并行:任何时候都同时有多个进程在多个CPU内在真的同时运行。


(4)阻塞状态

阻塞状态对应于进程的S状态和D状态。

所谓阻塞,即等待,等待键盘资源是否就绪,键盘上面有没有被用户按下的按键,按键数据交给进程。

当某个进程需要通过外设获取数据时,其本身会从进程的运行调度队列里断开,而连入外设的等待队列中,此时即为阻塞状态,当获取到数据后,则会重新回到进程运行队列

阻塞和运行的状态变化,往往伴随着pcb被连入不同的队列中,入队列的不是进程的什么代码和数据,而是进程的task_struct。

不是只有CPU才有运行队列,各种外设也有自己的wait_queue。


(5)挂起状态

当内存中有很多进程处于阻塞态时,大量的代码和数据导致内存吃紧,此时有一部分代码和数据将被唤出进磁盘的swap分区,从而减轻内存压力,当进程被唤醒时再将代码和数据重新唤入内存,我们将进程的代码和数据被唤出到磁盘的这种状态称为挂起状态


四.寄存器

CPU内部有非常多的各种各样的寄存器,会保存进程的临时数据,CPU内部所有寄存器中的这些临时数据称为进程的上下文。

当一个进程未执行完毕,但是需要临时停止而被切换执行其他进程时,寄存器会临时保存其上下文数据,并记录其当前代码的执行位置,等到该进程被切换回来时,再由寄存器恢复其上下文数据,继续执行该进程

寄存器本身是硬件,具有数据的存储能力,CPU的寄存器硬件只有一套。

CPU内部的数据,可以有多套,有几个进程,就有几套和该进程对应的上下文数据。

寄存器 != 寄存器的内容


五.进程优先级

指定进程获取某种资源(CPU)的先后顺序称为优先级。

linux中优先级数字越小,优先级越高

进程访问的资源(CPU)始终都是是有限的,所以要有优先级。系统中进程大部分情况都是有较多的。

操作系统关于调度和优先级的原则

分时操作系统,基本的公平,如果进程因为长时间不被调度,就造成了饥饿问题。


1.优先级特点及查看优先级

  • ps -al指令:查看所有启动的进程。
  • PRI:默认进程优先级,为固定数值(80)。
  • NI:进程优先级的修正数据,nice值,新的优先级=优先级+nice,达到对于进程优先级动态修改的过程。
  • nice值并不能被任意调整,而是有范围的。[-20,19]--40个数字。

优先级调整:

top指令:进入top指令后按“r”,回车,在输入进程的pid,回车,最后输入nice值。

每次调整优先级,都是从80开始的。


六.命令行参数和环境变量

1.命令行参数

** int main(int argc,char argv[])*

{}

main函数的参数可带可不带。

参数的意义

  • argc表示argv[]数组的元素个数。
  • argv[]表示一个字符串数组,以NULL结尾。

main函数的参数表示命令行中,用户输入的若干个指令(以空格为分界的若干个字符串)。

命令行参数本质是交给我们程序的不同的选项,用来定制不同的程序功能。命令中会携带更多的选项。

父进程的数据,默认能被子进程看到并访问。

命令行中启动的程序,都会变成进程,其实都是bash的子进程。


2.环境变量

  • linux中,存在一些全局的设置,表明,告诉命令行解释器,应该去那些路径下寻找可执行程序。
  • 系统中很多配置,在我们登录linux系统的时候,已经被加载到了bash进程中(内存)。
  • bash在执行命令的时候,需要先找到命令,因为未来要加载。
  • PATH:环境变量,是Linux系统下搜索可执行程序的默认路径
  • $PATH:打印环境变量内容。
  • 最开始的环境变量不是在内存中,而是在系统对应的配置文件中。
  • 环境变量具有系统级的全局属性,因为会被子进程继承下去。
  • 本地变量只在本bash内部有效,无法被子进程继承下去,只有导成环境变量,才能被获取。

bash进程启动的时候,默认会给子进程生成两张表:

**用户输入命令行形成的:argv[]命令行参数表;从OS配置文件中得到的:env[]环境变量表。bash会通过各种方式将表交给子进程。 **

**echo $PATH:查看环境变量所处路径。 **

**sudo cp/rm XXXX 路径:让XXXX可执行程序成为(去除)某路径下的系统可执行程序。 **

PATH=$PATH:路径:将某路径添加成为系统中搜索可执行程序的默认路径

系统的配置文件有:.bash_profile;.bashrc;/etc/bashrc

环境变量会在Linux系统重新启动时重新配置,所以只有在系统的配置文件中添加新的环境变量,才会永久存在。

  • env:查看系统所有环境变量。
  • echo $XXXX:查看单个环境变量。
  • export:创建新的环境变量。
  • unset:删除环境变量。

代码获取环境变量的方法:

头文件:#include<unistd.h>(前)#include<stdlib.h>(后)

  1. extern char **environ:声明全局的环境变量指针,用来获取环境变量表中的环境变量;
  2. 通过main函数参数;
  3. 使用getenv("环境变量")函数,获得指定的环境变量。

**linux系统中80%的命令由bash创建的子进程执行,称为普通命令,还有一些命令由bash亲自执行,称为内建命令。 **


七.进程地址空间

进程的代码和数据默认保存在内存中,但是进程不能直接从内存中获取数据,而是需要通过地址空间的虚拟地址,借助页表的映射得到内存的物理地址,进而访问到数据

地址空间的本质是内核中的一个struct结构体对象,内部很多的属性都是表示start,end的范围。

子进程会把父进程的很多内核数据结构全拷贝一份


1.写时拷贝

当一份全局数据被父子进程共用时,如果子进程对该数据进行修改,则会另开一个空间对原数据进行拷贝,再进行修改子进程指向新地址,父进程指向原地址,但两者表面上仍然共用同一个虚拟地址


2.为什么存在地址空间

通过页表映射将内存中无序的数据变成有序,让进程以统一的视角看待物理内存以及自己运行的各个区域。

能够使进程管理空间和内存管理空间结藕。

拦截非法请求,对物理内存进行保护。


3.理解虚拟地址

虚拟地址也叫逻辑地址,是程序中本身就有的地址

当程序加载到内存时,地址空间从程序获取数据,页表从程序获取虚拟地址,同时内存给出程序的物理地址,进而由页表组织形成映射关系


八.内核进程调度队列

Linux系统中每一个CPU都有一个运行队列:

从图中我们需要认识两个数组:

long bitmap[5]:32*5的160位的位图,用于判断队列某个位置是否存在进程。

task_struct queue[140]:后40位为进程队列,与进程的优先级40位nice一一对应。

其中,蓝色方框和红色方框为完全相同的进程队列结构,蓝色队列进程只出不进,红色队列进程只进不出,分别通过active和expired两个指针管理

当蓝色队列进程出完或红色队列进程进满时,两者会进行进出功能交换,实际为交换两个指针

这种进程管理方法称为大O(1)的时间片轮转调度算法


标签: linux

本文转载自: https://blog.csdn.net/2303_78442132/article/details/136641174
版权归原作者 很楠不爱 所有, 如有侵权,请联系我们删除。

“Linux——进程(上)”的评论:

还没有评论