(linux操作系统)从冯诺依曼体系结构到初识进程

什么是冯诺依曼体系结构

我们可以先看看下面的这张图片
在这里插入图片描述
到目前为止我们使用的电脑, 我们的手机,都是由一个个的硬件组成 大多数都遵循冯诺依曼架构,比如像我们的输入设备,电脑上的键盘,笔记本上的触控板,电脑硬盘等。 输出设备像电脑的显示器,手机的触摸屏等,电脑和手机都有中央处理器电脑是cpu手机是soc,他们内部都有运算器和控制器单元组成,电脑和手机都有运行内,所以他们都遵循冯诺依曼架构

根据体系结构我们知道,cpu只能和内存打交道,所有要cpu处理的数据都必须要加载到内存中去,根据上面的理解,我们要打开软件,cpu要处理软件信息,软件必须要加载到内存中去,才能被cpu访问,软件的信息会输出到屏幕上供我们查看,而软件被打开之前是存放在硬盘里面的,硬盘里面的东西就是文件,所以硬盘就像冯诺依曼体系结构里面的(input)输入设备,内存就是存储器,cpu就是运算器,控制器 屏幕就是输出设备

从数据层面理解冯诺依曼体系结构

根据上面的例子我们初步认识到了什么是冯诺依曼体系结构,现在我们从数据流动的视角切入我们在仔细理解一下,假如我们电脑上登陆了qq,我们要和别人聊天,本质上就是两个冯诺依曼体系结构在互相通信,别人的电脑上面也登陆了qq,现在我要发送一个你好到别人的qq上去,首先我们需要打开qq这个软件,qq就会从硬盘加载到内存中去,加载的过程就是拷贝的过程,把硬盘中的qq拷贝到内存中去,就相当于是把冷数据变成热数据可供cpu处理,现在内存中会分配一个区块给qq使用,我们从键盘上面输入“你好”,(从硬件层面来看) 本质上

就是把键盘上输入的内容通过键盘映射成一个值,给拷贝到内存中去,(从软件层面来看)就是把键盘输入的数据交给qq来处理,而在qq这个应用程序里面会有自己的加密算法,对输入的内容进行加密,会调用cpu的运算器和控制器执行自己特定的算法进行加密,加密完成之后,把要发送的数据从内存中拷贝给计算机的网卡,再由网卡输出出去,网卡会对数据进行特定的格式封装,封装成ip数据包,离开计算机,进入网络中去,再通过交换机,路由器,进行ip数据包的路由,最终到达对方计算机的网卡,此时对方计算机的网卡就是输入设备,然后网卡会把里面的数据给拷贝到内存中去,当数据到达内存中时,对方qq接受到了数据,会调用cpu中的运算器,控制器进行对数据的解密,解密完成之后就会输出到对方电脑的屏幕上。就完成了数据的处理与传输

在这里插入图片描述
有了以上的认知之后
我们再来说说,为什么现代计算机要遵循冯诺依曼体系结构,这主要是冯诺依曼体系结构里面引入了一个非常关键的东西,那就是存储器,也就是我们计算机上面的内存
在这里插入图片描述
为什么要这么说,我们可以来看看下面的图片计算机存储分级结构
在这里插入图片描述
计算机硬盘
在这里插入图片描述

内存
在这里插入图片描述

CPU缓存
在这里插入图片描述
其中内存对应分级图的位置是主存(dram)L3-L0是cpu内部的存储器,内存的响应时间是以纳秒计算的,而磁盘是以毫秒计算的,cpu的运算速度非常快,有了内存这个中间介,我们可以以低成本的方式很大的提示cpu的运算速度,我们根据以上图片不难发现,随着存储器等级的越高,他的速度就越快,但存储容量就越小,价格也就越来越贵,反之就越来越便宜,存储空间就越大,如果说冯诺依曼体系结构不要存储器,直接用cpu的缓存替换,那也不是不行,只不过价格非常的昂贵,不是一般人能消费的起的,所以现代计算机是性价比的产物,可以这样说没有冯诺依曼架构,计算机就不会普及,就不会有计算机网络的产生这就是为什么现代计算机要采用冯诺依曼架构。

有了上面的认知之后我们再来谈一个在计算机中也是非常重要的一个东西,那就是操作系统

操作系统

概念
任何计算机系统都包含⼀个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
• 内核(进程管理,内存管理,⽂件管理,驱动管理)
• 其他程序(例如函数库,shell程序等等
我们计算机里面为什么要有操作系统?我们可以看看下面的图片
在这里插入图片描述
上面的结构本质也属于冯诺依曼结构体系。
我们不难发现操作系统处于用户和计算机硬件交互的中间层,他在这个体系中起到承上启下的作用,对下,与硬件交互,管理所有的软硬件资源,对上,为⽤⼾程序(应⽤程序)提供⼀个良好的执⾏环境,当我们用户想用printf在屏幕上打印东西时,这个过程一定会贯穿整个结构,因为这个过程会涉及到硬件操作(显示器)

操作系统的目的是为上层用户提供更好的服务,手段是管理所有的软硬件资源!

有了操作系统我们用户才能更好的和计算机硬件打交道
在整个计算机软硬件架构中,操作系统的定位是:⼀款纯正的“搞管理”的软件

操作系统作为“搞管理”的软件,其核心职责是确保计算机系统的各个部分能够高效、稳定、安全地协同工作,为用户提供一个可靠的计算平台,同时也为应用程序的开发和运行提供必要的支持和服务

那么如何来理解管理呢?
我们可以举一个生活中的例子就拿大学中的校长,辅导员,学生之间的关系来举例子
校长想管理学生,不会亲自去找学生,而会去找辅导员去下达自己的要求,让辅导员执行,让辅导员去通知学生,从这个例子里面,我们可以看出,校长管理学生,并没有和学生亲自见面,而是通过辅导员这里我们引出一个结论:
要管理,管理和被管理者,不需要见面!

校长要管理学生,要知道学生的个人基本信息,肯定不会去一个一个的问,而是有一份所有学生的基本信息的一个数据表,表里面的每一行是一个学生的基本数据,要管理,直接对表里面的东西进行增删查改,在把结构回馈到辅导员那里,再让辅导员去执行去通知学生,这里我们又可以引出一个结论:
要管理,管理和被管理者,怎么管理呢?—通过数据管理!
那么校长如何得到所有学生的数据呢,那肯定是通过辅导员的统计,再把统计结果反馈给校长
这里又可以引出一个结论:
不见面,如何得到数据?—从中间层获取,这里的中间层就是辅导员!

操作系统中的管理也如此,在操作系统管理硬件的过程中,操作系统就是校长,硬件就是学生,各个硬件的驱动程序就是辅导员,操作系统直接通过数据对硬件进行管理,并不需要和硬件直接见面,而数据又是通过驱动程序获取的
那么操作系统到底是通过怎么的方式管理硬件的呢?

是一个先描述后组织的过程! 我们通过上面的例子也可以看出来,校长管理学生先把每一个学生的基本信息给描述出来,再按照特定的方式进行组织(这个组织方式可以是一个excel表格,或者其他的方式),而操作系统也是如此操作系统会给每个硬件创建一个结构体对象,再通过某一种数据结构把他们组织起来每一个结构体里面会描述对硬件的基本信息,方便操作系统对他们进行增删查改

总结

计算机管理硬件

  1. 描述起来,⽤struct结构体
  2. 组织起来,⽤链表或其他⾼效的数据结构

系统调⽤和库函数概念

在说这个之前,我们需要明白一个东西,操作系统要为我们提供服务,但是他不相信我们任何人,
我们现实生活中的银行和这个也是一样的,银行不相信我们任何人,但是他要为我们提供存钱取钱的服务,我们去银行办理服务,不可能有机会进到银行的金库里面,而是通过取号排号到窗口办理服务,我们可以把操作系统内核理解为银行的金库,他不相信我们任何用户,但会向上暴露一些接口供用户,开放调用,而暴露的接口就像银行的窗口柜台一样。

系统调⽤在使⽤上,功能⽐较基础,对⽤⼾的要求相对也⽐较⾼,所以,有⼼的开发者可以对部分系统调⽤进⾏适度封装,从⽽形成库,有了库,就很有利于更上层⽤⼾或者开发者进⾏⼆次开发。
在这里插入图片描述

有了以上的了解,我们来看看进程;

进程

有了上面的了解,操作系统是怎么管理进程的呢—答案是通过先把每个进程给描述出来,再组织起来进行管理的,也是一个先描述后组织的过程!

我们来看看教科书是怎么定义进程的

课本概念:程序的⼀个执⾏实例,正在执⾏的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体。

这个概念这么看感觉有点抽象,在我们平常通俗的认为进程就是一个在硬盘里面的一个可执行程序,被cpu加载到内存里面去了,一个在内存里面的应用程序就是进程,但是这样的吗?我们根据上面的结论,操作系统管理进程是一个先描述后组织的一个过程,但是这里描述都没有描述,那么操作系统怎么组织管理呢,显然不是这样的,真实的情况是进程在操作系统内核里面有自己的数据结构对象,在操作系统内核之外的内存里有自己的代码和数据所以说进程=内核数据结构对象+自己的代码和数据!
我们来画图看看
在这里插入图片描述
而内核数据结构对象是一个结构体,这个结构体称为PCB(process control block)linux系统西的pcb是task_struct
这个结构体里面包含了
在这里插入图片描述

可以这么理解PCB就相当于一个进程的简介,这个简介里面有相关进程的基本信息,操作系统就可以根据这些基本信息可以找到进程具体所在的位置,从而对这些进程进行管理,进程的所有属性都能从task_stuct里面找到。
task_struct是Linux内核的⼀种数据结构,它会被装载到RAM(内存)⾥并且包含着进程的信息。

task_struct内容分类

标⽰符: 描述本进程的唯⼀标⽰符,⽤来区别其他进程。 • 状态: 任务状态,退出代码,退出信号等。 • 优先级: 相对于其他进程的优先级。
• 程序计数器: 程序中即将被执⾏的下⼀条指令的地址。 • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
• 上下⽂数据: 进程执⾏时处理器的寄存器中的数据[休学例⼦,要加图CPU,寄存器]。 • I∕O状态信息:
包括显⽰的I/O请求,分配给进程的I∕O设备和被进程使⽤的⽂件列表。 • 记账信息:
可能包括处理器时间总和,使⽤的时钟数总和,时间限制,记账号等。 • 其他信息

有了以上的了解,我们在从linux实体机上面查看一个进程看看
我们切换到proc文件夹目录下,这个目录就是我们当前运行的进程,这个目录里面的所有东西都是在内存中的,有点类似于windows下面的任务管理器,他和磁盘没有任何关系。
我们历史上的所有命令,指令像ls,pwd之类的,还有自己的程序运行起来都是进程,只不过像命令这些进程创建的很快,销毁的也很快。
在这里插入图片描述
在这里插入图片描述
我们可以写一个程序来看看我们自己创建的进程
在这里插入图片描述
当我们的程序运行起来之后我们用: ps ajx | head - 1;ps axj | grep test 这个命令来抓取一下我们运行的进程
ps(是查看进程的命令)ps axj中的a就是表示所有进程的意思,如果我们只想查看我们自己创建的进程就使用ps axj | grep test就可以了,在linux中 | 管道操作符,可让我们同时输入多条指令,而这里我们输入的命令的意思是:显示进程信息的首行摘要;查找包含“test”的进程。
在这里插入图片描述

我们可以看到我们进程对应的pid号是8093 ,ppid号是 6461 pid号是 8093 PID是进程标识号,PPID是父进程标识号。 当我们使用上述方法不管查找任何进程时都会发现grep会一直存在,这是什么原因,我们根据上面的理解,我们输入的命令指令都是一个进程,那自然而然的grep也是一个进程,所以他也会被查出来 (因为我们查找想查看的进程时调用了grep) 如果我们不想要grep显示出来呢,那就可以使用下面的命令:ps ajx | head -1;ps axj | grep test | grep -v grep 就不会把grep显示出来了,grep -v 表示反向匹配,包含的grep不要,不包含的就留下来。
在这里插入图片描述
如果说我们想要杀掉进程一个办法就是使用ctrl + c 另一个方法就是使用kill -9 + pid号,来杀掉进程
在这里插入图片描述
有了以上对进程的认识之后,我们再回到proc这个文件夹下面
在这里插入图片描述

左边蓝色的部分他是代表的是进程号,他是一个目录,我们把我们的test进程给运行起来,然后进入到他所对应的进程号里面的文件夹去看看
在这里插入图片描述
这里面就包含我们对应进程的一些描述信息,我们这里就只关心两个一个exe,另一个是cwd,exe就是可执行程序后面跟了一个目录就是可执行程序的具体位置,而cwd就是current work dir这个意思是当前工作目录,当程序运行起来时,该程序进程会记录当前的工作路径,当我们有了这个了解之后,我们就可以得到一个结论为什么c语言的fopen当找不到指定文件时会在该程序运行的当前目录下新创建一个文件,他是这么找到这个路径的呢,答案是通过cwd找到的!
我们知道程序运行时都会加载到内存中,如果我们这时候把磁盘中的可执行程序删除了会怎么样呢,我们来试试
在这里插入图片描述
当我们执行完这个之后,我们发现我们的进程还在运行,我们再去查看一下当前目录的exe
在这里插入图片描述

发现exe这个地方标红了,提示test已经被删除,这也反过来说明了进程运行确实会被加载到内存中去。

下面我将讲解如果不用命令,在编程中手动创建进程,在说这个之前我们要先看一个函数
我们看看这个getpid这个函数的定义
在这里插入图片描述
还需要看看fork这个函数
在这里插入图片描述
linux所有的进程都是由他的父进程创建的,linux中没有母进程,是一个单亲繁殖的一个系统
我们下面写一个代码看看

在这里插入图片描述
我们运行看看
在这里插入图片描述
我们多运行一下看看
在这里插入图片描述
我们发现这个父进程一直是6190这一个,这个是什么进程呢,我们可以去查看一下
在这里插入图片描述
我们发现这个父进程是一个bash,这个bash是linux中的命令行解释器,linux会给每个登陆用户分配一个bash,这个bash本质也是一个进程,他会先启动printf打印然后再scanf,当我们往里面输入东西的时候像输入pwd,ls这些命令之后,输进去的值会再创建一个进程,用来给我们提供pwd ls这样的服务,这些都是由bash创建的进程,所以bash是父进程,pwd ls是子进程,包括我们运行的自己写的程序也是一样的。在windows中我们运行的应用程序一般的父进程是文件资源管理器。
那么进程是怎么创建进程的呢
也就是我们上面提到的fork()函数;
我们来一个样例看看;
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
现在我们让子进程和父进程执行两个不同的代码逻辑
我们来看看fork这个函数返回的值
在这里插入图片描述
成功时,父进程得到子进程的PID,子进程得到0。
失败时,父进程得到-1,并且不会创建子进程,同时会有一个错误码来指明失败的原因。

根据上面的返回值我们来创建一个能让子父进程执行不同代码的程序
在这里插入图片描述

在这里插入图片描述
现在我们这个代码可以根据子夫进程不同的返回值来执行不同的代码。
现在我们提出几个问题

  1. 为什么fork给父子不同的返回值?
  2. 为什么一个函数能返回两次?
  3. 为什么一个变量即可以==0又>0导致if else同时成立?

首先我们来说第一个,我们要知道一点,一个父进程下面可以有多个子进程,而子进程只有一个父进程,父进程和子进程的关系是1:n。(1对多的关系)。

然后我们来说第二点,我们来画图看看

在这里插入图片描述
现在来说说第三点 :我们先来谈谈return,return的本质是返回数据,那么我们拿一个变量来接受这个返回的数据,是不是就相当于修改这个变量的数据,也就是在写入变量
我们要知道一个道理当子进程创建的时候,他是和父进程共享代码和数据的,代码是只读的,如果说子进程或者父进程要修改数据,那么操作系统会在内存中拷贝一份数据供子进程或者父进程进行修改,不会影响到其他的进程,这个过程叫写时拷贝这个写时拷贝让进程具有独立性!子父进程之间不会相互影响!像我们上面的例子,id这个变量被父子进程进行写入,会在内存中开辟两个空间把他给拷贝过去,供父子进程使用。
所以:一个变量即可以==0又>0导致if else同时成立!
我们可以来验证一下
在这里插入图片描述

在这里插入图片描述
通过上面的现象我们修改子进程的数据并没有影响父进程!
完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值