Linux进程概念

一、对操作系统的浅显理解

1.冯诺依曼体系

要对操作系统有个基本的认识和印象,我们先得对冯诺依曼体系有一个认知

什么是冯诺依曼体系?

冯诺依曼体系包括了输入设备、输出设备、储存器、运算器和控制器,它将计算机的结构简单抽样成了这五个部分,按照上述链接方式,是一个简单的计算机组成模型

输入设备:键盘、话筒、摄像头、网卡、磁盘...

输出设备:显示器、磁盘、网卡、音响...

储存器:简单的理解就是我们电脑中的内存

运算器和控制器:也就是常说的CUP

计算机为什么要按照冯诺依曼体系?

计算机的本质就是对信息进行处理和运算,如此自然是需要输入和输出,并且需要运算所以CUP也是必要的,那么为什么需要内存?

存储数据的设备我们可以用磁盘去进行存储,然后运算通过cup运算,然后再进行输出,中间为什么需要经过内存?

这是由于外设(输入输出设备)对数据处理的速度相比于CUP慢特别多,如果将内存去掉,那么整体的效率就是以外设为主

这样对于CUP的运算效率是及其浪费的,因此,中间加入了一个内存,内存的效率比外设快,比CUP慢,我们可以将外设的数据进行预加载到内存中,那么CUP在访问数据进行运算的时候,就可以直接和内存进行沟通,整体的效率就会以内存为主

以上,我们首先对冯诺依曼体系有个基本的印象,然后就是可以得到一个重要的结论:

在数据层面,CUP和外设不直接进行沟通,都是通过内存进行数据交换的

2.操作系统(OS)

什么是操作系统?

操作系统是一款对计算机软硬件资源做管理的软件,其本质是软件

为什么要有操作系统?

因为要给用户提供良好(安全、稳定、高效、内容丰富)的计算机使用环境,对软硬件做管理是实现良好环境的手段

操作系统怎么样实现的管理?(简单理解)

操作系统通过结构体的方式去对描述要被管理的资源的信息,再通过各种合适的数据结构去将不同信息进行管理,也就是先描述,再组织

例如进程管理、内存管理,文件管理,驱动管理

二、进程

1.进程的概念

对于进程的理解,为了方便接下来的学习,进程不能只是简单的理解成正在执行的一个程序,我们看待进程要看到进程的代码和数据和内核对进程的数据结构,即:

进程 = 内核中关于进程的数据结构 + 进程的代码和数据

如上图,当一个可执行程序被执行,首先代码和数据会被加载到内存当中,然后操作系统在管理进程相关的部分会生成一个描述进程的结构体进行对这个可执行程序的管理。

2.PCB ——— 描述进程的结构体

PCB就是描述进程的结构体,在Linux操作系统下叫 task_struct ,里面包含着进程的各种关键属性

内容

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

3.查看进程信息

Linux下查看进程信息

指令ps

ps axj | head -1 && ps axj | grep myfilename(文件名字) | grep -v grep

这句指令的意思就是,找到指定文件名字的进程信息

路径 /proc

cd /proc

该路径下也可以查看所有进程的信息

4.进程的标示符(PID)

类型于编号一样的东西,每个进程都有自己的PID

我们可以通过查看进程信息去查看一个进程的PID,也可以通过系统调用,也就是写代码的方式去得到PID

getpid()     (头文件是#include<unistd.h>)

5.初识父进程和子进程

fork() 函数可以创建一个子进程,当创建成功后,子进程和父进程共享同一份代码和数据,但彼此之间具有独立性(即子进程对数据的操作,不影响父进程),fork()执行完后会产生一个子进程,和父进程同时继续往下执行代码,并且fork函数会带回一个返回值,当进程创建失败则会返回-1,创建成功则对子进程返回0,父进程返回>0的数。

运行结果

根据查看不断查看进程信息会发现,在Linux下运行的所有程序,它父进程的PID是固定的,通过指令可以找到,其父进程就是bash,这是为了保护bash进程不会挂掉,当子进程出现了问题,子进程挂掉不会影响到父进程

6.进程状态(STAT)

需要理解进程状态,我们需要先理解两个概念阻塞挂起

阻塞:等待某种资源,而暂时不被CUP调度的情况,也就是“卡了”

挂起:当内存不够用或者一个进程长期处于阻塞状态时,操作系统可能会将其代码和数据先放到磁盘当中,当资源就绪需要被CUP调度的时候,再将资源交换回来。

首先,我们要知道,CUP在一个时刻下,只能执行一个进程,我们看到的多进程同时运行,是因为CUP计算的速度快,多进程同时推进,而并不是某一时刻下能够同时的运行。

此外,一个进程在进行运行的时候,可能需要各种资源,例如网络、又或者cin函数需要输入等等,当一个进程需要等待某种资源的时候,CUP就会优先运行其他的进程,也就是这个进程阻塞了

因此,一个进程在内存中并不是一定处于运行的状态,有各种不同的状态,也就是我们接下来要总结的进程状态

R运行状态(running)

 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

S睡眠状态(sleeping)

 意味着进程在等待事件完成,也就是上面提到的阻塞状态的一种情况(这里的睡眠有时候也叫做可中断睡眠
(interruptible sleep))。

D磁盘休眠状态(Disk sleep)

有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束,这种情况一般不会出现,这是一种不能被操作系统干掉的阻塞状态,一般是由于向外设输出或者输入数据,为了保护数据不会丢失,所以保证该进程不能被操作系统中断

T停止状态(stopped)

 可以通过发送 SIGSTOP (kill -19)信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT(kill -18) 信号让进程继续运行。当使用这些信号改变状态后,程序会变成后台运行,此时Ctrl+c没法停下,可以使用kill -9,干掉进程

ps:调试是一种追踪暂停状态,一般是t

X死亡状态(dead)

这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

Z(zombie)-僵尸进程

僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程,僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

Z状态是为了让父进程(OS)拿到子进程的退出码,结束进程后的一个过渡状态

孤儿进程

父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
父进程先退出,子进程就称之为“孤儿进程”
孤儿进程被1号init进程领养,当然要有init进程回收喽

7.进程的优先级

概念

cpu资源分配的先后顺序,就是指进程的优先权(priority)

优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。

还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

查看系统进程

ps -l

其中有几个重要的信息

UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值,nice值是用来调整进程的优先级的,范围是[-20,19]

修改进程的优先级

我们可以通过修改nice值去调整PRI ,PRI(new)=PRI(old)+nice,注意,这里的PRI(old)是固定值为80

修改方式:

先使用指令top,然后按r,再输入需要修改的进程的编号(PID),然后再输入nice值

三、环境变量

1.概念 

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,从相关的系统文件中读取的。

如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

环境变量参数被放在一张表里,也就是字符串数组char* env[ ]中,在Linux下可以通过env指令调用来看到,也可以通过main函数的参数接收或者函数调用拿到

环境变量通常具有全局属性,可以被子进程继承下去

2.常见的环境变量

PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。

3.查看环境变量

echo $name (这里的name是环境变量的名称):查看某一个环境变量

env  :查看整张环境变量表

4.环境变量—PATH

PATH中存放的是Linux搜索指令的路径,Linux中的所有指令都是一个可执行程序,直接输入这些可执行程序的名称,Linux会默认去PATH设置的路径下查找,因此我们在执行我们自己的可执行程序时需要给指定的路径"./a.out" 而在输入指令时不用,就是这个环境变量的原因

因此,我们当然也可以将自己写的可执行程序添加到以上路径,改变环境变量中的PATH,将某个路径添加到里面,这样我们自己写的可执行程序也可以不用带 "./" ,就可以直接执行

设置新的环境变量的指令是export

例如:export PATH=$PATH:需要添加的路径

(注意,上面是将PATH修改为原有的加上添加的,不能直接等于某个路径)

5.关于环境变量的一些指令

1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量

6.环境变量表——environ

环境变量表记录着关于关于环境变量的各种参数,其本质是字符串数组(char* env[ ])

通过指令获取

通过代码获得

(1)通过main函数的参数

main函数有三个参数,其中env[ ]就是环境变量表,可以通过遍历的方式打印出来

前面两个参数的设计是专门为命令行参数设计的

(2)通过全局变量

#include <stdio.h>
int main(int argc, char *argv[])
{
extern char **environ;
int i = 0;
for(; environ[i]; i++){
printf("%s\n", environ[i]);
}
return 0;
}

(3)通过接口

#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}

四、虚拟地址空间(线性地址)

1.理解

虚拟地址空间是为了管理进程,在内存中虚拟出的一种数据结构,也就是我们经常写代码所认为的那个结构

进程中的task_struct记录的数据代码等等的地址就是虚拟地址的地址,通过页表一一映射到实际的物理内存当中,在真正需要使用空间时,再实际的给数据分配内存,也就是写时拷贝

2.进程如何使用虚拟地址

首先,一个可执行程序在磁盘中作为进程被运行时,操作系统会生成一个task_struct对该进程的信息进行管理,并且生成页表分配虚拟空间的地址,并且建立映射,但在实际物理空间的角度,未必会真的分配内存,当该进程被CUP执行且真正需要空间时,物理内存才会分配空间,CUP根据页表中的映射关系,通过虚拟地址找到物理地址对代码和数据进行处理

3.子进程和父进程为什么具有独立性

由于虚拟地址空间,子进程和父进程都是使用的虚拟地址,共享同一份代码和数据,而在真正需要执行和使用数据时,子进程和父进程分别都在物理空间中分配内存将数据拷贝,并且各自有不同的页表建立不同的映射关系,所以,在子进程和父进程中,我们可以看到同一个地址的数据,可能由于父子进程的不同,数据也会不同,对数据和代码具有独立性,这是因为在物理内存中,并就具有两个独立的空间去执行父子进程,父子进程中的数据地址虽然相同,但页表不同,映射到的位置也不同

4.虚拟地址的作用

1.防止地址被直接访问,页表的映射关系相当于在用户进行数据操作的过程中,中间加入了个软件保护层,防止越界访问等等问题,保护物理内存中其他数据和进程

2.将进程管理和内存管理进行解耦合

3.让进程可以通过统一的视角去看待内存,而实际的内存使用情况交给操作系统去管理

总结

本篇总结了与进程相关的一些概念,初步建立对进程和进程在内存中如何被管理和执行等等的印象,为接下来学习进程控制做基础

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-19 19:06:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-19 19:06:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-19 19:06:03       82 阅读
  4. Python语言-面向对象

    2024-03-19 19:06:03       91 阅读

热门阅读

  1. Python的Selenium库中的模块、类和异常的汇总

    2024-03-19 19:06:03       38 阅读
  2. 图像转pdf (python)

    2024-03-19 19:06:03       49 阅读
  3. C++/CLI学习笔记10(快速打通c++与c#相互调用的桥梁)

    2024-03-19 19:06:03       46 阅读
  4. Redis常见问题

    2024-03-19 19:06:03       41 阅读
  5. [蓝桥杯 2022 省 B] 修剪灌木

    2024-03-19 19:06:03       39 阅读
  6. JDK、JRE、JVM概念

    2024-03-19 19:06:03       43 阅读
  7. web蓝桥杯真题:商品销量和销售额实时展示看板

    2024-03-19 19:06:03       45 阅读