进程概念——Linux

时间:2023-01-23 09:51:08

“技术是时间积淀出来的,你能速成的东西,别人也可以速成,所以需要耐心学习”

猛戳订阅???????? ????Linux操作系统详解???? ????????

一、冯诺依曼结构

图片来自百度百科
进程概念——Linux
输入设备:键盘,话筒,摄像,(磁盘,网卡),C语言可以进行文件操作,所以磁盘可以作为输入设备。

输出设备:显示器,音响,磁盘,网卡,甚至显卡也是输出设备。

运算器+控制器(CPU):运算器进行了算数计算和逻辑计算。
控制器主要协调数据搬到内存,或者从内存搬到外设。
cpu只能被动的完成某种功能,相当于工具人,一般都是需要配合操作系统完成的。

存储器:这里的存储器指的是内存,内存不是磁盘。
除了内存之外的设备几乎都是外存。

为什么要存在内存?

CPU内包含了许多寄存器。寄存器的速度是非常快的。

CPU的运算速度 > 寄存器的速度 > L1~L3 > 内存 > 磁盘 > 光盘

一般来说速度越快价格越高。

假如只有输入设备 ——CPU——输出设备。
则效率会很低。效率由最低的设备决定,符合木桶效应。

以为输入设备和输出设备的速度比CPU慢很多。所以这时候冯诺依曼加了一个内存。

内存的速度比外设快,但是比CPU慢,所以可以把数据提前加载到内存,等待CPU读取和输入。

内存先接受输入设备的数据,然后把数据传给CPU计算,CPU再返回给内存,然后内存再输出到输出设备。

内存在我们看来,就是体系结构中的一个大的缓存,用来适配CPU和外设速度不均的问题。

从数据角度来讲:
外设和CPU不直接打交道,而是和内存打交道。

内存存在的最大意义:使用较低的钱,获取较高的性能。

我们都听过一句话,程序在编译好之后,必须先加载内存。
因为CPU需要与内存交互,所以需要先将编译好的代码编译到内存。

我们开机的时候就是把操作系统加载到内存。这就是预加载。

局部性原理

提前把数据加载到内存中,叫做局部性原理。
大概就是假如你现在正在执行第10行代码,则操作系统可以提前把你的第11行以后的代码都提前加载到内存。

这样就可以提高整个计算机的效率。

比如你刚打开计算机他比较卡,但是用了几十分钟后就不卡了,这就是提前加载到内存的好处。

二、操作系统

操作系统是一款软件,是一款搞管理的软件。

什么叫做管理?

所谓的管理就是决策者拿到相应的数据通知执行者,来对人进行间接地管理。

决策者就相当于操作系统,中间执行的人是驱动,硬件就是被管理者。

管理的本质就是对数据的管理——对数据的管理再转换为对数据结构的管理。

管理的核心的概念:先描述,再组织
先描述对应先创建结构体。
再组织对应进行链表链接。

比如写学生信息管理系统,我们先定义结构体来描述对象,然后再定义结构来组织这些对象。

所以我们需要学习 语言+数据结构。

语言是用来描述对象,数据结构是用来组织对象。

什么叫做进程?

操作系统包含四个管理模块:
内存管理 、进程管理、文件管理、驱动管理。

进程概念:进程就是一个运行起来的程序
这是肤浅的说法,实际上是将进程的结构体+进程的代码合起来才叫做进程。

操作系统里面能同时存在大量的进程,操作系统需要将所有的进程管理起来。

对进程的管理,本质就是对进程数据结构的管理。
所以这时候就用到先描述,再组织了

在Linux中,描述采用的是task_struct这个结构体,这个结构体里面包含了单个进程的所有数据。

组织采用的是链表结构。

在操作系统这门学科中,很多教材叫进程为PCB,叫做进程控制块

进程 = 对应的内核数据结构+可执行程序
也就是进程控制块=进程结构体+进程代码。

所谓的管理进程就是管理PCB的数据结构。也就是对链表的增删查改。

进程我们学什么?

学进程里面的属性

OS内核

OS内核需要直接管理驱动软件。

操作系统的管理结构如下

操作系统是一个封闭体,只暴露出一些指定的系统调用接口来供用户使用,这是操作系统为了保护自己。因为操作系统不相信用户。

因为Linux是用C语言写的,所以所谓的接口就是C语言给我们提供函数调用。

比如我们使用cout函数,本质是将数据写到硬件上,因为自己的程序没有资格写到硬件上。因为cout调用的是C++库,也就是用户操作接口,再调用系统调用接口,系统调用接口通过操作系统来管理打印到显示屏上。

操作系统是通过系统调用的方式,对外提供接口服务的。

后面学习的Linux系统编程,本质就是在学习操作系统提供的接口。

因为系统调用的接口对于一些用户来说不会用,所以这时候就在上一层有了shell外壳,C函数库lib,部分指令等,
shell叫做命令行解释器。

还有windows的图形界面,可以让小白使用。

某个语言具有跨平台性,就是因为它的lib库帮你实现了不同平台系统接口的调用。
这个和C++的多态的概念差不多。

三、Linux可以打游戏吗

可以打,但是Linux系统的用户少,一般人都用windows上打游戏。所以说游戏开发商一般不会在Linux发布开发游戏。毕竟不赚钱。

比如华为的鸿蒙操作系统,因为华为有手机作为资本,所以系统出来后,自动有供应商来找鸿蒙来提供各种软件。

四、ps axj显示自己的进程

1.ps axj 可以显示所有进程,这是后期最常用的一种方式。

//可以过滤出来关于mytest关键字的进程

ps axj | grep 'mytest'

因为Linux上的命令都算是进程,所以grep也是一个进程,所以以上命令会显示两个进程,一个是grep的一个是mytest的

加上-v grep后则不显示带有grep的进程
只会显示自己的进程。

ps axj | grep 'mytest' | grep -v grep

在/路径下存在一个proc的文件,里面存放的是进程的实时信息。上面的数字叫做PID,(process id)PID是一个进程的唯一标识符。
pid的意义就是快速找到进程。
进程概念——Linux

进程的pid会随着进程的关闭和启动,重新分配pid,所以进程的pid会变化的。

五、查看进程的信息

信息中的exe代表进程对应的可执行程序的磁盘文件。

cwd代表的是文件所在的当前路径。
所以说C语言为什么写的文件就在当前路径?

所谓的当前路径就是进程当前所维护的路径。

那么pid和cwd的路径信息都在哪呢?
这些都算是进程的内部属性,内部属性都属于数据,数据存储在进程控制块PCB中。

六、怎么绕过C语言直接调用系统接口?

显示信息列表并显示带有a.out的进程。

ps ajx | head -1 && ps axj | grep 'a.out' | grep -v grep

进程概念——Linux

获取进程的pid

以下获取pid是系统调用

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>                         
int main()
{
  while(1)
  {
    printf("process  pid :%d\n",getpid());
    sleep(1);
  }
  return 0;
}

假如要杀掉该进程可以按ctrl + c
也可以用命令

kill -9 进程的pid

-9就是发送9信号

七、创建进程的方法

1.把你写的程序运行起来,也就是创建进程

不管程序结束和运行,父进程一直不会改变,因为父进程就是bash。

几乎我们在命令行上所执行的所有指令(ls pwd cd等),都是bash的子进程。

fork()代码创建子进程

fork()函数的功能就是创建一个子进程。

fork给有两个返回值,给父进程返回子进程的pid,给子进程返回0。

这和C语言不同,C语言中不能同时执行if又执行else。

但是fork()函数可以同时运行。因为fork之后,父进程和子进程会共享代码,一般都会执行后续的代码。
所以会打印两次。

因为父子进程的返回值不同,所以可以通过不同的返回值判断,让父子执行不同的代码。

fork如何做到会有不同的返回值?

因为父进程和子进程是一对多的,所以父进程必须有标识子进程的方案,所以fork之后,给父进程返回子进程的pid。

给子进程返回0的原因是因为,来判断子进程是不是创建成功了。

为什么fork会返回两次?

fork有两个返回值,说明曾经被返回了两次。
fork是怎么做到返回两次的?
fork()函数是通过操作系统的system call实现的。
fork()之后,OS做了什么?

进程就是= task_struct+ 进程代码和数据

子进程的task_struct内部的数据基本是从父进程继承下来的。

子进程的代码是和父进程共享代码的。但是数据要各自独立。

虽然fork之后代码共享,但是可以通过不同的返回值执行不同的代码,比如用if,else分流。

如何理解进程被运行?

就是进程在运行队列中被CPU调度。

八、操作系统进程状态原理

以后谈到进程必须先想到进程的task_struct
这是结构体里面包含进程的全部信息。

Linux内核对进程的管理就是管理task_sturct的。

计算机学科的哲学科目——操作系统
所以我们具体事情具体分析,以Linux系统为例来学习Linux系统的进程状态。

运行态

进程只要在运行队列中,就叫做运行态。
每个CPU都要维护一个runqueue。这个运行队列每个元素就是PCB,也就是Linux中的task_struct,可以通过task_struct可以找到代码和数据。因为结构体里包含了指向代码的指针。

运行态不代表正在运行,而是代表可以随时被CPU调度

终止状态

所谓的终止状态也就是这个进程还在,只不过永远不会运行了,随时等待被释放。

为什么不立马释放资源?有没有可能操作系统正在忙着别的事情,所以没空来释放。

终止的意思就是我已经结束了,不能被调用了,随时等待释放。

进程阻塞(重点)

概念进程等待某种资源(非CPU),资源没有就绪的时候,进程需要在该资源的等待队列中进行排队,此时进程的代码并没有运行,进程所处的状态叫做进程阻塞。

在操作系统学科中,经常会听到阻塞状态。
1.一个进程,使用资源的时候,可不仅仅是在申请CPU资源!
2.进程也可能同时在申请其他资源,比如:
磁盘,网卡,(比如渲染)显卡资源。

如何进程申请CPU资源时,无法得到满足。这时候需要排队。这个队列叫做运行队列

那么如果我们申请其他慢设备的资源。比如磁盘。也是需要排队的。
总之,进程申请资源是需要排队的

概念:当进程访问某些资源(磁盘,网卡),该资源如果还没有准备好,或者为其他进程提供服务。此时:操作系统做了以下工作。
1.当前进程要从runqueue中移除
2.将当前进程放入对应设备的描述结构体的等待队列。

此时,我们的进程在外设等待资源时,该进程的代码不会被执行。这时候就叫做进程阻塞

在我们windows界面中,表现出来的状态就是软件卡住了。

通常电脑卡是在打开很多应用的时候会卡。
这时候可以把后台进程关掉一些。

进程挂起(重点)

就是进程处在非运行状态。

假如进程过多,内存不足了怎么办?
这时候操作系统就要帮助用户进行辗转腾挪。

短期内不会被调度(你等的资源短期内不会就绪)的进程,**它的代码和数据依旧在内存中。**这就是白白的浪费空间。这时候操作系统就会把该进程的代码和数据置换到磁盘上。

这样的行为就叫做进程挂起。进程挂起在小白看来,也是卡住了的现象。

九、Linux进程状态

进程后面加上+加号,叫做前台进程。前台进程可以ctrl+c杀掉。而后台进程需要用kill -9 命令。

R:运行状态,只要在运行队列就行。

S(sleeping):浅度睡眠,对应的就是阻塞状态。也就是在等待某种资源。一旦资源就绪就可以转换为R状态。此时也可以杀掉该进程。

D(disk sleep):这个状态也是一种阻塞状态,在Linux中这个是针对磁盘(disk)资源的等待。也叫深度睡眠状态,操作系统无权利杀掉该进程,只能等待该进程结束。
除非关机,或者拔掉电源。

Z(zombie):叫做僵尸状态。当Linux中的进程退出的时候,一般不会直接进入X状态,而是进入Z状态。

进入Z状态的原因是因为: 该进程退出的时候需要将执行结果告知给父进程。就是为了维护退出信息,可以让父进程或者操作系统来读取。

Z状态就是:如果创建了子进程,子进程退出了,父进程不退出,也不等待子进程,子进程退出后的状态就是Z状态。

假如一个进程正在处于僵尸状态,假如没有人回收,则该进程将一直维护!该进程的相关资源(pcb)不会被释放。这就叫做内存泄漏!

X:就是死亡状态,可以随时将资源回收。

T/t(stopped):大写T叫做暂停状态,比如暂停正在下载。 就是常规的暂停,小写t是进程被调试的时候,遇到断点所处的状态。就会呈现小t,也叫做追踪状态。

孤儿进程

孤儿进程是父进程先退出,子进程永远没退出,这时候子进程就变成了孤儿。所以叫做孤儿进程,孤儿进程则由ppid为1的父进程来领养。

父进程的父进程是bash,bash会自动回收父进程。

十、进程优先级

优先级是进程获取资源的先后顺序

为何会存在优先级

优先级就是排队。为什么存在优先级?本质原因是因为资源不够。所以才需要排队。

PRI和NI

NI是nice值,可以调整优先级
PRI越小则优先级越高。

Linux中更改优先级是更改NI,而不是更改PRI。

改变优先级命令如下

sudo top

NI的取值范围为-20到19。【-20,19】
PRI = PRI+NI;

每次调整NI都PRI初始值都是80.