理解Linux中的OS管理和进程属性

冯诺依曼体系结构

冯诺依曼体系结构:

输入设备,输出设备,存储器,中央处理器(CPU)

存储器指的是内存

CPU包括运算器和控制器

CPU在数据层面,不会和外设直接打交道,只会和内存进行交互

任何程序在运行时,都必须先从磁盘中加载到内存

因为代码和数据必须被CPU访问,但是CPU指挥和内存进行交互

这是体系结构决定的

数据流动eg.

为什么要有内存?

内存时外设和CPU之间的一个巨大的缓存

操作系统(OS)

任何计算机系统都包含一个基本的程序集合,称为操作系统

操作系统包括:内核,其他程序

OS的本质时一种进行软硬件资源管理的软件

设计OS的目的

每一种硬件都要有自己对应的驱动程序

与硬件交互,管理所有的软硬件资源

为用户程序提供一个良好的运行环境

管理是先描述再组织

进程

什么是进程

进程是程序的执行实例,是正在执行的程序

进程是担当分配系统资源的实体

进程 = 内核数据结构(task_struct) + 程序的代码和数据

在调度进程时,会让task_struct进去排队

进程会被根据task_struct属性,被os调度器调度运行

task_struct内部有哪些属性:

标示符

ps ajx | head -1 && ps ajx | grep 执行文件名可以查看运行中程序的属性

将程序运行起来(./或双击)的本质,就是启动一个进程:

执行完就退出(ls, pwd指令)

一直不退,直到用户退出(常驻进程)

pid

怎么显示进程的标示符(PID)

同一个进程再不同时间启动,其PID是不一样的,因为PID是累加的

PID是为了区别进程

在进程中使用 getpid 就可以获取pid

在系统中可以使用ctrl c来终止运行中的进程

也可以使用kill,kill可以向指定的进程发送信号

kill -9 pid编号 可以杀掉一个进程

在linux系统中可以使用ps来查看文件的属性

根目录下的**/proc**中的每一个目录即代表一个进程

目录的名称就是pid

目录中存储的是该进程的属性

当启动进程时,系统会紧接着在/proc中新建一个相应的文件夹

ps的本质就是打开/proc

cwd:current work dir(当前工作目录)

当前路径就是进程的cwd

当一个进程实际启动的时候,该进程会记住当前的路径(cwd)

启动进程时,会在当前路径生成文件,这个路径就是文件的cwd

chdir可以改变进程启动时的路径

这样就可以让其他的文件在别的路径生成

ppid

ppid是父进程id

在Linux系统中启动后,新建任何进程时,都是自己的父进程创建的

使用getppid()可以获取父进程id

命令行中,执行命令/程序,本质是bash进程创建的子进程,由子进程执行我们的代码

子进程

fork()函数可以创建子进程,创建成功会给父进程返回子进程的pid

可以看到这里打印了两个分支printf

因为经过fork分支后,会执行两个分支

fork()函数由两个返回值

因为fork后变成了两个进程

这两个进程是父子关系

一般而言,这两个进程的代码是共享的(子进程的代码是从父进程继承来的)

但是数据是各自私有一份

fork()返回的id对于父进程是subpid

对于子进程是0

为什么父子进程的数据各自私有?

进程具有很强的独立性,多个进程之间,运行时,互不影响,即便是父子

一个进程在运行时,代码是只读的

但是数据不允许两个进程互相干扰,因此要保证数据各自私有一份

返回的本质就是对指定的变量写入数据

而打印的数据就是读取数据

创建多进程

创建子进程时,子进程的task_struct是拷贝自父进程的

然后再调整新的task_struct部分属性

task_struct连入到进程列表中

此时子进程已经创建了

父进程执行一次return,子进程执行一次ruturn

所以fork()会存在两个返回值

fork后,谁先运行是由OS的调度器来自主决定的

状态

进程的状态

CPU执行代码,不是把进程执行完毕才开始执行下一个

而是给每一个进程预分配一个时间片

基于时间片进行调度轮转(单CPU下)

这种行为是并发

多个进程再多个CPU下同时运行

这种行为是并行

Linux/windows民用级别的操作系统

分时操作系统,调度任务追求公平

实时操作系统,从开始到结束,必须尽快处理,且一但运行就尽量跑完

一个进程位于运行队列当中,该进程就叫做运行状态

本质是准备好了,随时可以运行

数据没有准备好,导致进程无法运行,则是阻塞状态

运行和阻塞的本质是让不同的进程处在不同的对列中

当内存严重不足时,系统会将进程挂起到外设

在磁盘中单独设有一个swap分区用于挂起

挂起的本质是用时间换空间

Linux进程的状态

R(running):运行状态

S(sleeping):休眠状态,阻塞等待的状态,可中断睡眠,浅睡眠

D(disk sleep):磁盘休眠状态,阻塞等待状态,不可中断睡眠,深度睡眠

该进程在睡眠期间,不可被杀掉

T(stopped):停止状态

t(tracing stop):追踪停止

进入停止状态的原因:

1.进程做了非法但是不致命的操作,被OS停止了

2.当进程被追踪断点停下,进程状态是t

使用 kill -19 可以让进程停止

使用 kill -18 可以结束停止状态

X(dead):终止状态

进程创建出来,是为了完成用户的任务

通过进程执行的结果来告知父进程/操作系统,任务是否完成

Z(zombie):僵尸状态

维持退出信息,方便父进程和操作系统来进行查询

进程退出时

1.代码不会执行了,首先可以立即释放的就是对应的程序信息结构

2.进程退出,要有退出信息(进程的退出码),保存在自己的task_struct内部

3.管理结构task_struct必须被OS维护起来,方便用户未来获取进程的退出信息

进程创建时,先创建task_struct,再有代码和数据

进程退出时,先释放代码和数据,再删除task_struct,还没有删除task_struct时,进程时僵尸状态

僵尸进程如果没有人管,则会一直僵尸,僵尸进程默认没人管

如果一个进程僵尸,父进程不进行回收,就是内存泄漏

语言层面的内存泄漏问问题,如果在常驻内存的进程中出现,影响比较大

父进程还在,子进程退出,则正常

父进程退出,子进程还在,子进程会被系统领养

这种子进程是孤儿进程

进程优先级

优先级是获得某种资源的先后顺序

排队的本质就是确认优先级

为什么要有优先级:

因为目标资源较少

优先级就是task_struct中维护的int类型

优先级数字越小,代表优先级越高

优先级受PRI和NI影响

PRI(priority):Linux中的进程的优先级

NI(nice):优先级的nice数据(-20 <= nice <= 19)

最终优先级 = pri(默认/老的) + nice

uid是用户id,决定了进程是谁启动的

为什么nice存在范围?

为了保证进程调度的尽量公平

为什么是[-20,19]?

真实进程的优先级范围是[60,99]

相同优先级的进程会被挂接在一起

修改优先级不是高频操作,而且不建议修改,可以使用指令或代码进行修改

进程队列

CPU里面维护了有两张相同数据的哈希表

active(活跃)和expired(过期)

CPU调度只会从active队列中选择进程进行调度

通常哈希表中纵向根据优先级排队,横向根据到来的先后顺序排队

为了防止进程饥饿问题

创建的新进程和时间片结束的进程会被放到expired对列中

只有当active对列为空,才会将expired中的进程放入active对列中(直接将两个对列的指针交换)

同时又维护了两个bit_map[5](位图)来决定对应为止是否存在进程

这是LInux内核O(1)调度算法

所有进程都要链表链接

但是linux中的链表结构与一般结构不同

只有连接字段,没有属性字段

为什么要设计成这样?

一个进程,既可以在全局链表中,又可以在不脱离全局链表的同时,加入别的链表

原理:

同一个结构体中定义的对象,其地址时相邻的,并逐渐递增

这样只要知道其中一个对象的地址,并知道该对象的偏移量,就可以知道整个元素的地址了

进程切换

每个进程都有一个时间片,时间片到了,就要切换进程

Linux是基于时间片进行调度轮转的

一个进程在时间片结束时,不一定跑完,可以在任何地方被重新调度切换

CPU

eip(pc):当前正在执行指令的下一条指令的地址

ir:指令寄存器,就是正在执行的指令

CPU内部的寄存器的数据,是进程执行时的瞬时状态信息数据

CPU内有很多个寄存器,整体称为一套寄存器,寄存器不等于寄存器中的数据

进程切换的核心是进程上下文数据的保存和恢复

其本质就是

切走:将相关寄存器的内容,保存起来

切回:将历史保存的寄存器的数据,恢复到寄存器中

每次切换时,每次保存完上下文的时候,CPU都是全新的

一套寄存器是被多个进程共享使用的

进程的上下文寄存器数据,被保存到当前进程的PCB中就可以了

进程运行就是重复"取指令,更新pc,分析执行指令"的过程

相关推荐
十五年专注C++开发2 小时前
cpolar(极点云): 一款主流的内网穿透工具
linux·windows·cpolar·穿透
徒 花2 小时前
HCIP学习05 链路聚合(Eth-Trunk)+ VRRP
服务器·网络·学习·hcip
liliangcsdn2 小时前
LLM如何与mcp server交互示例
linux·开发语言·python
小夏子_riotous2 小时前
openstack的使用——7. 共享文件系统manila服务
linux·运维·服务器·系统架构·centos·openstack·运维开发
Omics Pro2 小时前
上海AI Lab+复旦大学:双轨协同实现自动化虚拟细胞建模
运维·人工智能·语言模型·自然语言处理·数据挖掘·数据分析·自动化
南境十里·墨染春水2 小时前
linux学习进展 进程的内存管理
linux·服务器·学习
Bert.Cai2 小时前
Linux cp命令详解
linux·运维
一个人旅程~3 小时前
macOS装进移动硬盘成为双系统的操作方法
linux·经验分享·macos·电脑
哇蛙蛙3 小时前
H3CNE--23.ACL
服务器·网络·经验分享·网络协议·tcp/ip·h3cne