Linux——进程的概念(上)

目录

一、冯诺依曼体系结构

(1)概念

(2)结论

二、操作系统

(1)前置知识

(2)设计OS的目的

(3)作用

(4)小总结

三、系统调用和库函数的概念

四、进程

五、task_struct(pcb)

1、内部结构

(1)如何得到该结构体变量的其实地址

(2)如何访问该结构体变量内部的任意一个属性

2、内容分类

3、查看进程

getpid()

getppid()

4、bash如何创建子进程

(1)fork

(2)/proc系统查看(不常用)

(3)ps

5、进程状态 

(1)多进程程序书写

 (2)传统操作系统(教材上)

(3)运行状态(新建状态)

(4)阻塞状态

(5)挂起状态


一、冯诺依曼体系结构

(1)概念

  • 截止目前我们所认识的计算机,都是由一个个的硬件组件组成的
  • 存储器:内存
  • CPU——运算器:算数运算,逻辑运算
  • CPU——控制器:执行代码,进行逻辑控制
  • 输入设备:键盘,话筒,摄像头,键盘,网卡
  • 输出设备:显示器,键盘,网卡,打印机

(2)结论

  • 由上图可知CPU在数据层面,不和外设打交道,只会和内存打交道 
  • 数据流动的本质就是拷贝,计算的整体效率,本质是在设备间拷贝的效率
  • 内存的本质:是外设和CPU的缓存(效率:输入设备(外设)<< 内存 << CPU,如果使用都是用CPU来处理,成本十分高,如果使用外设根据木桶原理那么他的效率就会取决一外设,效率低下,所以映入内存使用冯诺依曼结构可以让用户用不那么高的成本获得效率比较高的计算机)
  • c++/c可执行程序为什么必须先加载到内存(预先加载):体系结构决定的。

二、操作系统

(1)前置知识

  • 操作系统:进行软硬件管理的软件
  • 任何计算机问题,都可以通过添加一层软件层来解决
  • 软硬件体系结构:本质是层状的

  • 任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)包含:内核(进程管理,内存管理,文件管理,驱动程序)其他程序(例如函数库,shell程序)

(2)设计OS的目的

ps: 硬件是通过冯诺依曼结构来组织的

(3)作用

  • 对下:管理好软硬件资源(手段)
  • 对上:给用户提供一个良好(稳定的,安全的,高效的)运行环境(目的)
  • 如何理解管理我们举一个例子,我们将学校成员分为三类 校长   辅导员    学生校长是管理者   辅导员是决策的执行者  学生是被管理者

  • 由上方和对关系的理解可知 管理员  要管理  被管理者 不需要见面见面不是必要条件,获取你身上的有效信息才是管理的必要条件(例如这里校长通过辅导员来获取学生的信息),管理本质是对数据的进行管理(例如校长要对排名前几的人发放奖学金,本质是对成绩这一数据进行处理)
  • 如何数据进行管理:先描述,在组织(描述:类,结构体 。组织:数据结构(最常用链表),容器技术)

(4)小总结

  • 操作系统是由什么语言写的? C语言
  • 描述事物:struct
  • os内一定存在大量的数据结构 (有进程 ,文件, 内存,驱动管理)
  • 所以学操作系统之前,一定要了解os内各种数据结构

三、系统调用和库函数的概念

  • 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
  • 系统调用在使用上,功能比较基础,对用户的要求相对比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发
  • 例子:

  •  如上图银行中提供金库电脑等接口,但是她不可能让群众直接和金库和电脑接触所以她封装了一层银行系统(窗口)通过它来使用接口这就叫系统调用,但是有一些人搞不懂她要去拿一个窗口,所以银行会设置一个大堂经理来帮助她,这个就叫库

四、进程

五、task_struct(pcb)

进行先描述再组织(使用双链表)

1、内部结构

Liunx如何通过 双链表管理task_struct的

想象的

实际的

并不是首尾用双链表而是体内的一部分,通过双链表将他们链接在一起 

目的:我们实现的双链表,再也和类型无关了

例:我们可以在task _struct 插入多个双链表或者我们将task_struct 列入到调度队列当中而不破坏其他的结构(如将全局链表断链),我们也可以将链表插入其他类型之中,不需要单独再实现双链表

小问题

知道结构体内任意一个成员的起始地址和结构体类型

(1)如何得到该结构体变量的其实地址

 该成员的起始地址- 偏移量

以struct test 为例

(2)如何访问该结构体变量内部的任意一个属性

该结构体的首地址->任意一个属性

2、内容分类

标示符:描述本进程的唯一标示符,用来区别其他进程

状态:任务状态,退出代码,退出信号

优先级:相对于其他进程的优先级

程序计数器:程序中即将被执行的下一条指令的地址(如PC)

内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针

上下文数据:进程执行时处理寄存器中的数据

I/O状态信息:包含显示I/O请求,分配给进程的I/O设备和被进程使用的文件列表

记账:可能包含处理器时间总和,使用的时钟总和,时间限制,记帐号等

其他信息

3、查看进程

我们首先写一个程序让她死循环,这样我们就能让进程一直能运行,从而我们能观察进程的现象

getpid()

查找进程的pid值

本质是系统调用,系统不允许直接访问,所以提供了一个接口

./myprocess.c形成进程等到pid

getppid()

获取父进程(Linux系统,增多进程是靠父进程来创建子进程的方式,让Linux系统中的进程变多的)的pid

如下图

我们能观察到每一次启动进程的时候父进程都不变,查看父进程 

结论:我们在命令行中,启动命令/程序的时候,都会变成进程,该进程的父进程是bash 

4、bash如何创建子进程

底层使用fork创建子进程

(1)fork

创建子进程

因此我们可以观察到打印了两份

例:

 fork的返回值

我们观察到fork成功后,,会有两个返回值

给父进程返回子进程的pid,给子进程返回0.

验证: 

小问题

返回值什么是这样?父返回子进程pid,子进程返回0

父进程和子进程的关系是    1:n;从子进程找父进程很容易,从父进程找子进程很困难所以我们需要父进程返回子进程的pid保存,当有需要的时候通过它找到对应的父进程

一个函数怎么可能有两个返回值

我们知道数据是从磁盘拿到内存中在生成一个task_struct维护代码和数据

1、在Liunx中,创建一个新的子进程,子进程的task_struct,也要被初始化,以父进程位模板(个别的地方进行改动)

2、fork创建的子进程,该子进程默认好像没有自己的要执行的代码和数据——默认共享父进程的代码和数据(即默认情况下共享fork之后的代码和数据(后面的虚拟地址中详细述说))

3、fork本质是一个系统调用它会进行上述的操作,所以我们知道fork之后的所有都是共享的(即执行两边),return也是一个语句所以它也会执行两次

验证:

fork之后的代码和数据执行两次

同一个变量,为什么即==0又>0; 

在下面的虚拟地址中详细述说

(2)/proc系统查看(不常用)

/proc可以查看所有正在进行的进程(当进程结束该进程就会在/proc中消失)

 通过它可以查看我们运行的进程

由上面可知进程会记录默认路径(也就是当前路径——就是当前进程路径),例如我们在新建文件的时候没有指明位置会在当前路径下新建,这里的当前路径就是默认路径

验证:

chdir可以改变当前路径

 

如上图当前路径已改 

(3)ps

ps axj:打印所有的进程的信息

过滤

 验证

5、进程状态 

(1)多进程程序书写

ps:当我们创建子进程之后,父子两个进程,谁先运行,不确定由OS根据调度原则来确定

 

 (2)传统操作系统(教材上)

状态,决定了进程接下来要做的工作 在本质就是一个数字,我们可以通过定义不同的数数字来定义不同的状态,上图是所有操作系统,在实现进程状态变化的时候,都要符合上面的理论

Liunx的运行状态,阻塞状态,挂起状态

前提知识:

进程竞争资源本质就两类资源

1、CPU资源

2、外设资源

(3)运行状态(新建状态)

运行状态:该进程的PCB必须处于CPU的调度队列中,(只要在调度队列中,进程就叫做运行状态随时等待CPU调度执行)

(4)阻塞状态

例:

如下就是阻塞状态

操作系统是一款操作管理系统,硬件需要先描述再组织

如上图的例子,我们需要键盘的输入,此时如果键盘没有输入就是阻塞状态,该PCB就会从运行链表中断链移动到键盘队列中等待。

总结:

阻塞和运行的本质:

1、更改task_struct状态属性

2、列入不同的队列中

(5)挂起状态

当内存的资源不够的时候操作系统换出进程的代码和数据(进行磁盘的该区域叫做swap区)

分类

把阻塞状态的代码和数据进行挂起叫做阻塞挂起

把没调度的进程进行挂起叫做就绪挂起(严重内存不足)