linux基础5:linux系统(冯诺依曼体系结构+os管理+进程状态1)

冯诺依曼体系结构+os管理

一.冯诺依曼体系结构:

1.简单介绍(准备一)

在这里插入图片描述

常见的输入设备:磁盘 ,键盘,鼠标,摄像头,麦克风,声卡,网卡,数位板。
常见的输出设备:显示器,声卡,网卡,打印机。
输入+输出:声卡,网卡。
cpu的功能:进行运算操作+控制cpu的信息流动。
存储器就是我们的内存:所以的设备都只能和内存打交道。

2.场景:

1.程序的运行:

一个程序的运行是直接加载到内存当中的!

在这里插入图片描述

2.登录qq发送消息:

在这里插入图片描述

3.为什么需要内存:

1.简单的引入:

1.假设我们的体系结构中只有输入设备,输出设备,cpu三个主要部分?
2.结论:系统效率大大降低,效率只取决与输入输出设备:

在这里插入图片描述

2.计算机存储体系:

在这里插入图片描述

1.从上到下速度越来越慢:
2.造价越来越便宜:
3.每级之间效率相差不大:

3.内存的意义:

1.因为cpu直接和输入输出设备进行交互太缓慢:运行程序多的时候就只能看输入和输出设备:
2.输入设备的中的可执行程序加载到内存中cpu没有执行之前程序都可以预先加载到内存中。
3.cpu要进行运算就从内存中去拿到程序。
4.执行结果也可以在内存中进行保存让输出设备一个一个的拿出去。

有了上面两个知识的铺垫我们就可以解释内存存在的意义:

1.整个系统的效率就由内存的效率决定了:
2.减少了使用成本并且体系结构使用稳定:
3.综上所述:整个硬件体系就不存在影响效率的问题了,转换到了软件的问题,整个机器的效率就要看操作系统了。

二.操作系统:

1.概念引入:

1.操作系统本质是一个软件,是第一个软件。
2.操作系统和底层硬件之间的联系结构图。

在这里插入图片描述

2.故事引入:(校园环境做背景)

校长—>做决策:
辅导员—>保证管理和决策落地:
学生---->被管理人:

1.管理者和被管理者是不需要见面

1.管理者和被管理者之间是通过管理者获取到被管理者的信息进行管理本质上是对信息做管理。

2.管理者如何获取被管理者信息?

1.通过辅导员拿到被管理者的信息!

3.数据量较大的时候怎么办?

1.当管理者在面对大量的被管理者的时候,这么多的数据如何去处理?把对人的管理变成对数据的管理!

4.建立学生的数据结构:保存在容器中

1.我们知道每一个学生都有相同的属性不同的内容,每一个学生的属性内容都是不一样的。
2.建立学生结构体,把信息保存在容器中,进行对学生数据的管理:
3.对学生的管理就转移到了对容器的每一个学生信息结构体的增删查改。

5.总结:管理的过程就是一个 先描述再组织的一个过程!

通过上面的介绍:对于底层硬件的管理就是
1.操作系统(驱动管理)----------->校长。
2.硬件驱动-------->辅导员
3.硬件本身-------->学生
4.总结:对于硬件的管理本质上就是一个先描述再组织的过程。
描述:结构体进行描述 组织:使用数据结构进行组织
5.为什么需要操作系统?
5-1:没有操作系统需要自己管理和控制硬件:
5-2:对下:更好的控制软硬件资源:
5-3:对上:提供良好的运行环境:
5-4:稳定,高效,安全。

3.系统调用和库函数的概念:

1.基本概念:

1.在开发角度,对外会表现为一个整体,但是会暴露自己的部分接口,供上层进行开发使用,这部分由操作系统提供的接口叫做系统调用。
2.系统调用在使用上,功能比较基础,对用户的要求相对比较高,所以有心的开发者可以对部分系统进行适度的封装,从而形成了库,有了库,就更加利于用户的使用和开发者的开发。
3意义:解决系统调用:减少接口使用成本:
4.上面这个概念有可能不是特别容易听懂:说一个故事!

可以把系统调用接口想象成银行的取钱的窗口,一个比较会存取钱的人(不需要lib库可以直接和系统接口交互)来了呢可以直接取号去到窗口办理业务。那么现在有一位老大爷要来取钱老大爷什么也不会那么这个老大爷就找到了大堂经理(lib库),大堂经理就帮助老大爷进行拿号到窗口办理业务取钱的整个过程相当于调用系统接口借助了lib库的帮助一样。

在这里插入图片描述

2.从上到下需要注意的一些问题:

1.从上到下是不可以发生越级访问。
2.不可以绕过操作系统
3.操作系统从头到尾是贯穿的。

三.进程管理:

1.承上启下:

操作系统是怎么进行进程管理的呢?
非常简单先描述再组织的一个过程!

2.基本概念:

课本上:程序的一个执行实例,正在执行的的一个程序:
内核上:担当分配系统资源(cpu时间 , 内存)实体。

上面这些概念不是特别的好可以不看!用网上比较火的说法就是:如说!

2-1事实:

1.我们可以同时启动多个程序—多个exe加载到内存中:
2.操作系统需要管理多个加载到内存中的程序!
3.操作系统如何管理加载到内存中的程序呢?先描述再组织!

3.描述进程:PCB :task_struct(linux系统下)

task_struct(进程控制块:进程属性的合集) 是PCB的一种是linux系统下的描述进程属性的结构体,它会被装载到RAM(内存)里并且包含进程的信息。

4.场景一:加载多个程序到内存:

总结:
进程 = 可执行程序+内核PCB对象
进程 = 可执行程序+内核数据结构

在这里插入图片描述

5.task_struct 内容分类:

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

5-1:程序计数器

程序计数器: 程序中即将被执行的下一条指令的地址。
在这里插入图片描述

6.组织和查看进程:

1.PCB->task_struct :PCB操作系统规定的名称!
2.结构体中包含进程的所有属性:

在这里插入图片描述
在这里插入图片描述

6-0:在C/C++下获取当前程序的子父进程号的函数:

#include<unistd.h>
#include<sys/types.h>
1.获取当前程序的进程:getpid():
2.获取当前程序的父进程:getppid():

6-1:查看进程简单方式:

方法一:查看系统文件夹:/proc/ 下的进程信息!
请添加图片描述

方法二:通过命令进行查询:
ps ajx | head -1 && ps ajx | grep mybin
ps ajx 查看当前系统的所有进程
请添加图片描述

方法三:使用脚本进行进程的刷新:
while : ; do ps ajx | head -1 && ps ajx | grep mybin ;sleep 1 ; done
功能:可以进行实时的进程信息观察:
请添加图片描述

6-2:创建文件:

在这里插入图片描述

1.我们知道在C语言中我们使用fopen()函数打开一个文件进行只写操作,如果当前路径下没有这个文件会创建一个文件用来进行写入!
2.那么 这个路径在linux中是以什么进行保存的呢?
3.我们查看了proc中存放的该进程的程序:
cwd(当前工作路径):/LIMO/proc_learn/
exe(可执行程序的路径):/LIMO/proc_learn/mybin
4.fopen() 函数可以找到cwd的路径并且在这个路径下生成文件!

请添加图片描述

6-3:chdir() 修改当前工作目录:

在这里插入图片描述

动图效果:
请添加图片描述

7.系统调用创建进程——fork

7-1:创建子进程:

使用man fork 查看一下信息!
1.复制当前进程称为父进程生成一个子进程。
2.fork有两个返回值!
3.父进程拿到新开辟子进程的pid,子进程拿到pid为0的返回值!
4.子进程的意义,我们想要生成的子进程去给我们做事情!

在这里插入图片描述

 44 int main()
 45 {
 46     int n1=5;
 47     while(n1--)
 48     {
 49         printf("当前进程:%d 当前父进程: %d\n",getpid(),getppid());
 50     }
 51 
 52     pid_t tmp = fork();
 53     printf("程序pid: %d",getpid());
 54 
 55     while(1)
 56     {
 57         if(tmp == 0)
 58         {
 59             
 60         printf("当前进程是子进程的进程号:%d 当前父进程: %d\n",getpid(),g    etppid());
 61         }
 62         else
 63         {
 64 
 65         printf("当前进程是父进程的进程号:%d 当前父进程: %d\n",getpid(),g    etppid());
 66         }
 67         sleep(1);
 68     }
 69     return 0;
 70 }

//观察一下动图效果:

在这里插入图片描述

7-2:三个问题:

1:给父进程返回子进程的pid 给子进程返回0?

父进程:子进程 = 1:n 一个父进程有可能有多个子进程,所以想要父进程可以确定的找到某一个子进程就需要返回子进程的pid 。对于子进程来说父进程只有一个所以找到父进程是非常容易的所以返回0;

2:一个函数只能返回一个值?这个tmp有两个值?返回了两次吗?

fork()函数的实现:
在这里插入图片描述

子父进程共享变量,在return的时候发生写时拷贝变量名是相同的,地址不相同,进程号不相同,拷贝使用不同的内存空间!在linux下可以使用同一个变量名表示不同的内存!

3:if 和else 的判断都满足条件说明 tmp==0 并且大于0?

这个问题需要一些后面的知识以后再说!

4:一个进程奔溃了影不影响另一个进程?

命令: kill -9 进程号 :单独杀死一个进程!

动图效果:
在这里插入图片描述

8.进程状态:

8-1:进程排队:

在这里插入图片描述

1.进程具有这样的连接状态,只要进程的task_struct 进行这样的排队。直接连在这个地方。我们只要有这个节点就可以找到这个链表,就可以链入全局双链表或者链入队列!

问题一:需要找到结构体的首地址!

在这里插入图片描述

找到了task_struct 的首地址就可以对对象数据进行任意的访问!
在全局还是任何队列消息非常容易找到!

问题二:队列:

1.进程·不是一直在运行的(有可能在等待软硬件的资源)进程放在cpu中也不是一直都会运行的!
2.只要是进程排队就是pcb排队!
3.如何排队就是通过struct listnode 结构体保存信息进行排队!

8-2:状态:

运行,阻塞,挂起:都是一个状态这些状态都有对应的队列!
进程的一个状态就是:进程在状态队列进行的一个排队!把对应的struct listnode 加到保存的对应的位置!

这些状态是如何进行保存的呢?

struct task_struct {
int status;
……………………
}

#define New 1
#define Ready 2
#define runing 3
#define block 4

8-3:运行:

1.一个cpu一个运行队列:
2.struct runqueue{
int num;
task_struct* q ;//保存了pcb中的struct listnode 这个对象的地址!
}
3.已经加载到运行时队列,表示的意思是我已经准备好被随时的进行调度了!

在这里插入图片描述

8-4:阻塞:

在这里插入图片描述
在这里插入图片描述

1.这个时候就进入了阻塞状态。
2.为什么产生?需要获取软硬件的资源所以进入阻塞状态!
3.阻塞状态是有一个阻塞队列的和运行队列是一个作用!
4.阻塞队列(等待队列)是由对应的的硬件提供的!
5.进程进入等待队列是把进程链入底层设备的一个过程!
6.对于设备来说输入数据完成就是表示硬件已经就绪?这个状态只有操作系统最清楚!操作系统在这个地方就进行了管理!

总结:进程在等待软硬件资源的时候,如果没有准备好我们的task_struct
1.将自己设置为阻塞状态,进入对应软硬件提供的等待队列。
2.把自己的pcb链入对应软硬件提供的等待队列。
3.状态的改变,导致pcb会被os变迁到不同的队列中!

8-5:挂起:

1.进入挂起的前提是:资源已经非常吃紧了!
2.这个挂起也叫做阻塞挂起!
3.在阻塞状态下把进程相关的代码和数据转换到外设中节省内存空间。
4.意义:我们可以慢一些但是不可以为了快产生资源吃紧导致有可能最后操作系统就挂掉了!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值