『Linux』 第四章 进程—— 进程概念

目录

一、 前言

二、 什么是进程?

进程的基本概念

理解进程

三、 查看进程

通过 ps 命令可以查看进程

通过 ls/ proc 命令查看进程

cwd的作用

通过系统调用获取进程标示符


一、 前言

        通过上一节的学习,我们了解了操作系统是如何进行管理的,那么同理,对于进程,操作系统是如何进行管理的呢?

        很简单,先将进程描述起来,再把进程组织起来!

        那么进程又是什么呢? 下面我们就围绕进程进行讲解

二、 什么是进程?

  首先我们来看一个问题:

   操作系统能不能一次运行多个程序?    答案是肯定的

        因为操作系统运行的程序很多,所以操作系统需要将这些运行的程序管理起来。

而我们就将这些正在运行的程序称为进程。(是正在运行的程序叫进程,而并非是程序本身)

  •  如何管理这些进程呢? —— 先描述,在组织

      那么,操作系统是如何进行描述,以及组织的呢?

  • 操作系统会创建一个描述和控制该进程的结构体。这个结构体称之为进程控制块 (PCB,Processing Control Block里面包含了该进程几乎所有的属性信息(可以理解为进程属性的集合),同时CPU也可以通过进程控制块也可以找到该进程的代码和数据。
  • 在 Linux 中,进程控制块就是 struct task_struct 结构体。
  • 描述好所有进程了,还需要将所有进程的 PCB 给组织起来(通过双链表的方式),此时操作系统只需要拿到双链表的头指针,就可以找到所有进程的PCB。
  •  这时,操作系统 就把对进程的管理转换为了对数据结构中PCB的管理,即对双链表的增删查改的操作。

假设,有一个可执行程序test,它存储在磁盘上,就是一个普通文件,当我们 ./test 运行该程序时,操作系统会做出以下的处理: 首先在内存中,先为程序申请进程控制块(PCB),之后将程序从磁盘加载到内存中,并将PCB中相应的指针指向程序,至此就为该程序创建了对应的进程。

 总结: 

  1. 为什么要存在 PCB呢? —— 因为OS 要对进程进行管理
  2. 目前对于进程的理解: 进程 = 程序 (代码 + 数据) + 内核申请的与该进程所对应的数据结构(PCB)。

进程的基本概念

  • 【课本概念】: 程序的一个执行实例,正在执行的程序等。
  • 【内核观点】: 担当分配系统资源(CPU时间,内存)的实体。

当然,我们目前就可以在Windows系统下,直观的看到目前正在执行的所有程序,可以摁下【ctrl + shift + ESC】 打开任务管理器 查看

        这也就证实了,在一个操作系统中不仅只能运行一个进程,还可以运行多个进程。

        但是,为什么操作系统可以运行多个进程,CPU是如何对待这多个进程的。这个我们以后在做解释。

理解进程

    在了解了进程的基本概念后,我们在更加进一步地认识一下进程管理是如何实现的?

      还是那句话,先描述进程,构建一个抽象的数据体,再进行组织进程。

描述进程 —— PCB(进程控制块)

        我们对于不同事物的区分方式,就是通过各种不同的属性,故而我们将每个进程的各个属性集合到一个数据信息体中,之后对这个数据信息体进行组织,管理,就达成了进程管理的目的,而其中的数据信息体 就是 PCB(进程控制块)

  •  课本中的叫法是: PCB(Process Control Block)
  •  Linux 操作系统下的PCB 是: task_struct

        因为Linux 的内核源代码都是用C语言来编写的,所以linux的这 task_struct 实际上就是一个结构体,而这个结构体就是组织了各种各样的属性,去描述一个进程,Linux采取的组织方式是【双向链表】

        以下就是task_struct 的所有结构信息:

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

三、 查看进程

        接下来,我们就来看一看进程到底长什么样吧

测试代码

1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 #include <stdlib.h>
  5 
  6 int main()
  7 {
  8     while(1)
  9     {
 10         printf("I am a process! pid : %d, ppid: %d\n",getpid(),getppid());
 11         sleep(1);
 12     }                                                                                                       
 13     return 0;
 14 }

通过 ps 命令可以查看进程

通过 ps ajx 命令查看进程

接下来,我们来查看我们当前运行的测试程序的进程

ps ajx | head -1 && ps ajx | grep test

注: ps ajx  | head -1 可以显示进程头,也就是进程的标签头

        grep test  只筛选 test 进程

  那么, 我们查找的总共有三条,中间那条是我们运行的测试进程,那么其他两条是什么呢?

  •  第一条是我们系统中自带的test文件,test系统中是有同名文件的,所以我们在命令行,直接输入test 是可以运行的,而这个查找到的就是系统自带的
  • 第三条  grep  --color=auto test 这个进程,是grep也是一个程序,他要进行过滤,就要运行,运行了就也会产生进程, 这也证明了所有指令本质上都是程序,运行时也要变成进程

   那么,我们应该怎么才能过滤掉【grep】命令执行的进程呢, 其实只需在 原命令后面加个 -v grep 把其过滤掉即可        这样就只有我们执行的程序了

通过 ls/ proc 命令查看进程

我们都知道根目录下有很多的路径:

       其中,这个proc目录, 它是一个内存文件系统,里面放的是当前系统实时的进程信息。我们进入此目录看看:

         这些就是系统中的所有进程,它的文件夹名称就是对应进程的PID值。PID 就是我们上面介绍的task_struct (Linux下的PCB结构体)中的【标示符】,这个PID是描述本进程的唯一标识符,用于区别其他进程。

         之后,我们重新运行下,测试程序,进去测试程序的文件夹中看看

         这就是进程中的所有信息,我们换一种方式详细查看下

        其中,我们先看 其中的【cwd】这文件,可以看到它的文件类型是【l】,这个文件类型表示的 该文件是链接文件类似于Windows下的快捷方式,而cwd 的全称是 current work directory 当前进程的工作目录,所以,这个文件存储的就是这个进程的工作目录, 【exe】文件,指向的就是这进程的exe执行文件。

cwd的作用

        那么,cwd的作用是什么呢?

        我们可以在程序中在扩展一段代码,用于创建一个文件,然后我们可以观察看这个文件的创建位置。

可以看到,现在当前文件夹是没有文件的,接下来我们编译运行以下看看

        运行结束之后,我们可以看到当前文件夹中就出现了 这个新建的文件【log.txt】,而这也就说明一个情况,那就是当程序中创建的文件没有指定存放位置时,文件会默认放在进程中cwd所指向的位置,所以cwd的一个主要作用就是 —— 默认下载路径

通过系统调用获取进程标示符

        上面我们有提到过PID进程标示符,是通过ps这个命令来查看的,那么我们能否直接获取这PID呢?

        那么,我们能不能直接获取到每个进程的PID呢?

        在之前的文章中我们说到过操作系统是不会相信任何人的,所以操作系统只会提供给用户一些封装一些系统调用(库函数),那我们只需要通过这个系统调用即可获取到当前进程的PID值

    注: ps 的搜索进程对应的PID的方法,其实更像是遍历操作,只不过是我们在遍历的基础上增加了筛选操作,才使得能够看到所对应的PID,而下面要说的一种方法,是作用于程序中,获得该程序所对应的进程PID与PPID

         接下来,我们来讲解一下 获得PID的命令,也就是getpid()函数和getppid函数

        我们可以man 2 一下查看下

 下面这段命令,可以实时监控当前系统的进程

while : ;do ps ajx | head -1 && ps ajx | grep test | grep -v grep; sleep 1; done;

        然后,我们来运行一下命令,看是否真的能检测到相关的进程

 但是,我们多运行几遍,就会发现一个特点:

我们发现,每次重新启动程序时,PID 的值时会出现不同的,而PPID 的值是不变的,因为PID是子进程,而PPID是父进程,其实子进程就是父进程建立的,每次杀死的也都是子进程,所以每一次重启程序,都是父进程重新建立一个子进程,所以每次子进程的PID值是不同的,而父进程的PID却不改变。

        那么,我们去看看这父进程到底是什么东西

         这个bash 就是我们建立的程序的父进程,而这个bash是什么呢?

         其实,每次在登陆Xshell的时候,系统都会为我们单独再创建一个Bash进程,即命令行解释的进程,帮我们在显示器中打印出对话框终端

        我们在命令行中输入的所有指令都是Bash进程的子进程,Bash进程只负责命令行的解释

,具体执行出问题的时候只会影响它的子进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值