Linux—进程学习-01

目录

Linux---进程学习---1

1.冯诺依曼体系结构

冯·诺依曼提出了电子计算机系统制造的三个基本原则,即采用二进制逻辑、程序存储执行以及电子计算机系统由五个部分组成(运算器控制器存储器输入设备输出设备,其中运算器与控制器又共同组成为中央处理器CPU),这套理论被称为冯·诺依曼体系结构。

我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系

截至目前,我们所认识的计算机,都是有一个个的硬件组件组成

输入单元:包括键盘, 鼠标,扫描仪, 写板等

中央处理器(CPU):含有运算器和控制器等

输出单元:显示器,打印机等

关于冯诺依曼,必须注意几点

存储器指的是内存!,一定要注意!

磁盘和硬盘既可以是输入设备也可以是输出设备

不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)

外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。

总结一句话,所有设备都只能直接和内存打交道

**对冯诺依曼的理解,不能停留在概念上,要深入到对软件数据流理解上。比如:从你登录上qq开始和某位朋友聊天开始,数据的流动过程。**从你打开窗口,开始给他发消息,到他的到消息之后的数据流动过程。如果是在qq上发送文件呢?

那发文件呢?

其实也是一样的,只不过输入设备不在是键盘,而是磁盘 ,因为文件是存储在本地的磁盘中的,将文件从磁盘传输到内存,经过cpu处理之后,传输给网卡和显示器等输出设备,网卡通过网络将文件数据传输到另外一个用户的输入设备---网卡上,然后再加载到内存中,经过cpu的处理之后,传输给输出设备显示器。[此时用户一般可以选择下载到本地,即将文件从内存中传输到输出设备---磁盘上]

2.操作系统

2.1操作系统的概念

操作系统的概念:

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:

  1. 内核(进程管理,内存管理,文件管理,驱动管理)

  2. 其他程序(例如函数库,shell程序等等)

操作系统的本质就是一个对软硬件资源进行管理的软件

2.2操作系统的目的

其目的就是:

  • 通过对软硬件资源的合理的管理(手段),给用户创造一个良好的(稳定的,高效的,安全的)运行环境(目的)

2.3如何理解管理

操作系统是管理者,那谁是被管理者------其实是软硬件资源,下面是一个图,方便理解。

对于操作系统是如何对软硬件进行管理的理解图,有一个例子可以方便理解:

就像校长就是学生的管理者,校长不需要去接触每个具体的学生,但是仍然能够对学生进行管理,就是通过拿到学生的所有具体的数据,以数据的变化为依据,进行对学生进行管理的重大决策。

经过上图的理解,可以总结出------管理的本质就是对数据继续管理

那管理者是如何不断的拿到被管理者的数据,并根据数据的变化来下达相应的决策,对被管理者进行管理的呢?

这中间就还需要引出一个执行者的概念。

如果是在学校里,执行者可以是辅导员,可以是班长等其他位置,这里就当做辅导员。

如果是在操作系统中,若被管理者是硬件,那么执行者就是驱动

管理者(OS/校长)具体来说是如何管理被管理者的呢?

所有的管理本质的逻辑都是------先描述、再组织【也就是面向对象思维】

将被管理者的数据描述成一个类,然后再将类的对象用数据结构组织起来【将一个个类的对象用某个数据结构存储起来】,通过这个数据结构的一些算法【比如找到增删查改】来对数据进行管理

总结

计算机管理硬件

  1. 描述起来,用struct结构体

  2. 组织起来,用链表或其他高效的数据结构

2.4计算机软硬件体系的理解

此时有一个问题:**操作系统是不相信用户的,它不会将自己底层的进程管理、文件管理等、以及底层管理的数据开放给用户进行访问。**不然用户如果操作错误,就会导致操作系统崩溃。但是操作系统又需要给用户提供各种服务。不然用户怎么知道自己的硬件是什么情况呢?自己的文件什么情况等。

因此操作系统给用户提供了许许多多的接口来给用户使用。比如用户想往磁盘中存储一些数据,用户是不能自己往磁盘输入数据的,只能将这个申请提交给操作系统的接口,经过操作系统的判断之后,才会往磁盘输入数据。

就像我们不能直接拿钱去将钱存到银行的仓库中,只能交由银行的人员来完成这个操作一样

上面提到的这个操作系统的接口一般叫做系统调用

如果是Linux系统的系统调用,其实就是调用c式的接口、因为Linux系统是由C写的,也就是说系统调用其实就是OS提供的一个C语音编写的函数的调用

但是如果让用户直接去使用系统调用的话,也是不太好的,因为这要求用户对操作系统有一定的了解,不然是无法使用的、因此就会有一些上层的软件,比如指令操作(shell)和编程操作(c/c++)、来帮我们使用系统调用

下面是举例:

在shell中,我们输入ls或者touch等指令,其实都是通过调用shell的接口,这个接口和系统调用会有关系,因此最终还是在调用系统接口来完成对硬件的访问。比如ls就是将这个文件的内容全部输入,那不就需要读取磁盘内的空间并输出到显示器吗,touch指令也需要在磁盘中创建一个空间用于存放新建文件。这需要向磁盘空间输入数据,最终也是系统调用完成的工作、

在写c/c++代码的时候,printf和cout是调用库函数,库函数内部会有系统调用。最终仍然是通过系统调用实现的向显示器(硬件)输出

对于上面描述的计算机软硬件体系可以用一个图片来总结:

这里最底层的硬件需要了解冯诺依曼体系结构、

驱动程序是执行者,它执行操作系统的管理决策,并将硬件的数据变动交给操作系统,便于操作系统管理、

操作系统会将驱动程序先描述成一个类,并用如链表的数据结构将其组织起来、方便做出一个个对外界提供服务的系统接口、也就是系统调用

而在我们写代码或者输入指令的时候,涉及对硬件的访问,都是通过库函数来帮助我们使用系统调用,进而访问硬件、

2.5系统调用和库函数的概念

在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用

系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。

3.进程

3.1进程是什么

进程------一个被加载到内存的程序

内核观点:担当分配系统资源(CPU时间,内存)的实体。

3.2管理进程

首先程序是一个文件,因此,程序想要被运行,根据冯诺依曼体系结构,存储程序的文件必须要被加载到内存中。然后再被cpu计算,运行程序。但是很多时候,被加载到内存上的程序非常多、

这个时候被加载到内存上的程序非常多,此时就会有很多问题,先运行那个程序?程序的在内存的位置如何分配?那些程序执行过?那些程序没有执行过?有些执行完的程序要销毁释放,有些程序需要多执行几次等等问题。

因此操作系统为了更好的管理这些被加载到内存的大量程序文件,就将加载到内存的程序称作进程,然后管理这些进程。如何管理呢?

前面说了,管理的逻辑就是先描述、再组织。

因此操作系统对进程的管理自然也需要先描述、再组织

3.2.1描述进程-PCB

要相对进程进行管理,需要先将进程描述起来。如何描述呢?

在描述的时候,需要将进程其描述成一个类或者结构体。这个类和结构体中存放着进程的所有属性。

操作系统会用PCB来描述进程

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。

  • 进程控制块称之为PCB(process control block),Linux操作系统下的PCB是: task_struct

其实在Linux下的进程控制块(PCB)就是一个结构体,这个结构体放着进程的所有属性【比如进程的id,进程的优先级,进程的状态,进程的地址、以及各自属性等等】

要注意:这里所说的进程的属性,都是操作系统自己添加的,原本被加载到内存的可执行代码文件是没有这些进程属性的,它只有自己写的代码和数据逻辑

因此每一个可执行程序被加载到内存的时候,操作系统都会将其作为进程并将该进程的所有属性放到PCB中。

将进程描述成PCB之后,就要将PCB组织起来,方便管理

3.2.2组织进程

当内存中有多个进程的时候,就会存在多个进程控制块(PCB),操作系统就会将其用数据结构联系起来,将多个进程控制块用链表之类的数据结构联系起来。这样就实现了组织

这样组织起来了之后,如果cpu需要找到优先级最高的进程来执行,就只需要遍历进程控制块(PCB)的链表,找到优先级最高的进程,并执行就可以了。

如果进程执行完毕需要删除释放,只需要遍历PCB的链表,找到状态为死亡的进程,然后将其代码从内存释放出去,然后删除对应的PCB即可。

3.2.3总结

操作系统对进程管理,不是对进程本身进行管理,而是对进程控制块(PCB)进行管理、

如果是用链表将PCB组织起来,那么对进程管理就转化成了对链表的增删查

内核数据结构 用数据结构将内核结构体(task_struct)组织起来 -> 内核结构体 struct task_struct -> 内核对象 task_struct的对象->将该结构和你的代码和数据关联起来 ->先描述,在组织的工作
进程 = 内核数据结构(task_struct) + 进程对应的磁盘代码

linux内核的部分PCB(task_struct)的源代码:

这个结构体有300多行。比我在linux写的代码都多了

3.3查看进程

  • 大多数进程信息可以使用top和ps这些用户级工具来获取

下面是个例子,当ProCessOn代码正在执行的时候,可以输入ps ajx | grep 'ProCessOn'来抓取这个进程是否存在

如果想让抓取的进程的信息带上标题可以输入ps ajx | head -1 && ps ajx | grep "ProCessOn"

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

输入ls /proc

如果要获取PID为1的进程信息,需要查看 /proc/1 这个文件夹。

注意:

通过/proc来查看进程,这是一个内存级别的目录,可以显示当前正在运行的所有进程的pid,如果一个新的进程被创建,pid号是24641,那么在/proc目录也会出现一个24641的目录,可以进行查看,里面会有该进程的属性信息、

4.与进程有关的系统调用

  • getpid()

这个是c语言自带的接口,可以实现系统调用,拿到当前进程的pid

pid_t其实就是一个整形类型,按照整形使用即可

这里我写了个死循环程序

执行结果如下:

在另外一个窗口抓取进程

如果想要杀死进程,就输入kill -9 进程pid即可

  • getppid()

这个的作用就是获取父进程的pid

当我们运行多几次程序我们就会发现,进程本身是会变的,因为每次被加载到内存,操作系统都会为该进程重新分配pid。

但是父进程是不会变得,我们抓取一下这个父进程pid就知道了

可以看到父进程本身是bash,也就是shell本身

如果将该进程kill掉,那么就会直接退出这个命令行解释器。

  • 在命令行上运行的所有程序,其都是子进程,父进程一般情况下都是bash

这样有个好处,子进程有问题不会影响到父进程,父进程可以安全的运行下去

现在又有了一个新的问题,子进程是如何创建出来的,又是如何运行起来的呢?

等到学习进程控制就会明白了。

相关推荐
钊兵42 分钟前
数据库驱动免费下载(Oracle、Mysql、达梦、Postgresql)
数据库·mysql·postgresql·oracle·达梦·驱动
weixin_425878232 小时前
Redis复制性能优化利器:深入解析replica-lazy-flush参数
数据库·redis·性能优化
左灯右行的爱情2 小时前
Redis数据结构总结-listPack
数据结构·数据库·redis
anddddoooo2 小时前
域内证书维权
服务器·网络·网络协议·安全·网络安全·https·ssl
zhoupenghui1682 小时前
golang时间相关函数总结
服务器·前端·golang·time
lllsure3 小时前
Linux 实用指令
linux·物联网
隔壁老王1563 小时前
mysql实时同步到es
数据库·mysql·elasticsearch
努力的小T3 小时前
使用 Docker 部署 Apache Spark 集群教程
linux·运维·服务器·docker·容器·spark·云计算
想要打 Acm 的小周同学呀3 小时前
Redis三剑客解决方案
数据库·redis·缓存