【Linux从入门到精通】进程的基本概念

简介: 我们通过对上篇文章冯诺依曼体系结构对硬件进行讲解后, 本篇文章会对进程进行深入讲解。同时会讲解PCB(进程控制块)。希望本篇文章内容会对你有所帮助。

 我们通过对上篇文章冯诺依曼体系结构对硬件进行讲解后, 本篇文章会对进程进行深入讲解。同时会讲解PCB(进程控制块)。希望本篇文章内容会对你有所帮助。



一、再次理解操作系统


在学习进程之前,我们先来理解一下操作系统。我们学习完冯诺依曼体系结构后,知道计算机是由一个个硬件组成的。只有一堆硬件,计算机可以运行起来吗?答案是不可能的。还需要结合软件才能运行起来。例如最重要的软件:操作系统。


 前面的文章中我们提到,操作系统是一款管理软硬件的软件。我们这里就有很多问题:操作系统是管理哪些软硬件呢?操作系统为什么要管理呢?操作系统是怎么进行管理的呢?我们接着往下看。

1、1 操作系统的作用

 我们先来看一张图:




3db153b2c34b461eb68dde82e45f083f.png


我们用户是不会直接跟底层的硬件打交道的。首先,新手用户不懂底层硬件的使用。其次,底层硬件学习起来成本太高。我们所使用的都是可视化界面,一个个软件。而软件是怎么跟底层的硬件打交道的呢?原因是中间有一个操作系统。


 通过上图我们看到,我们作为用户都是在向计算机使用简单操作或发送许多指令,达到我们使用计算机的目的。而我们的每个操作是要贯穿操作系统,操作系统经过一系列操作将我们的指令“翻译”成底层硬件认识的指令,进而送达硬件部分。从这里我们了解到,操作系统有连接上层用户软件和下层驱动和硬件的作用。


 一个个硬件放在那里是不能运行起来的,他们之间需要产生联系。操作系统就是对下要管理好各种驱动程序和各个硬件资源,为上层的软件提供一个良好的运行环境。

1、2 操作系统的管理



在上节图片中看到,操作系统的主要的四个功能:内存管理、进程管理、文件管理、驱动管理。我们发现,操作系统主要就是进行管理的。那到底是怎么管理的呢?


 在这里举一个例子:学校管理学生。当一个学校只有几个学生时,那这个学校管理起来就很容易,并且可以很容易的记住这几个学生的所有信息。当学校有几千名甚至上万名学生时,管理起来似乎就并没有那么容易。为了更好的管理学生呢,学校会将所有学生的各种信息、属性统计起来,放在一张表格中。当需要看某个学生的成绩时,直接通过该同学的信息属性直接筛查出来即可。我们发现这样管理似乎就简单起来了。


 操作系统的管理也正是如此。对比上述的例子,我们知道操作系统中软硬件资源多而复杂(学生很多),为了更好的管理这些软硬件资源,可以先将这些软硬件资源进行描述(学生入学填写各种属性、信息),再通过各种高效的数据结构将他们组织起来(放到一张表格中,需要时可通过筛查直接找到)。


 通过上面的描述,我们总结管理其实就是先描述,后组织。这里我们再引入进程。那操作系统是怎么对进程进行管理的呢?我们可以直接理解操作系统是对进程先进行描述,再把进程组织起来。我们接下来进入我们主题:进程。

二、进程基本的概念

2、1 什么是进程

 我们在自己电脑上任务管理器下就可以查看进程,如下图:



9a56cebd8fa74222a0edfe37b801821d.png


 那到底什么是进程呢?

 我们在很多地方可能看到:加载到内存中的程序,就是进程。这种概念是正确的吗?我们不妨先接着往下探索一下。



2、2 进程控制块 PCB


在学习进程中,我们都知道每个进程都会有一个PCB。为什么呢?PCB又是什么呢?


 我们上述提到了,操作系统对进程的管理就是先描述,后组织。怎么对进程进行描述的呢?答案就是:进程控制块PCB是对进程描述的一个结构体。这里我们知道了PCB是用来描述进程的一个结构体。是为了我们后面对进程更好的组织和管理。


 在Linux下描述进程的PCB是task_struct。有很多同学会在这里有点搞不清楚了。PCB和task_struct到底是什么关系呢?这里给大家举一个例子:在现实生活中,我们都知道相亲都靠媒婆。你可能也认识几个媒婆,例如你的邻居王阿姨就是媒婆,我们也叫她为王婆。媒婆是一个统称,王婆就是媒婆中的一个具体的人。同样,PCB是进程控制块的统称,task_struct就是PCB中的具体的一种进程控制块。我们知道PCB是描述进程的一个结构体,


那么这个结构体中都有进程的哪些属性呢?我们接着往下看。

2、3 查看Linux上的进程

 我们在上面了解到进程后,我们不妨在Linux下查看一下进程。我们先在Linxu下写一个C语言代码,代码如下:

  #include<stdio.h>                                                                                                                                            
  int main()    
  {    
    while(1)    
    {    
      sleep(1);    
      printf("hello OS,pid";    
    }                                                                                    
    return 0;                                                                            
  }


我们写的是一段无限循环的代码。是为了我们后面可以更好的观察进程。我们编译生成 myporc 的可执行程序。查看进程的指令是:ps axj | head -1 && ps axj | grep "proc"。我们可看下图一起理解:


889dd92b4a5349b4b721e45376374561.gif


当我们结束程序后,我们就会发现进程中就不再有该程序,如下图:


f6a49f062abb477dafe5393fb70f5282.png


我们曾经所有运行创建的程序,本质上都是在内村上创建进程

2、4 再次理解进程


 问题回溯:加载到内存中的程序,就是进程吗?


 这里举个例子:在清华大学里面的学生就算是清华大学的学生吗?你可能会说是的。那么问题来了。我现在确实是一个河北省的大学生,我现在坐个火车来到清华了,我就是清华的学生了吗?想得美ovo!是清华的学生就应该有清华的学生证。


 加载到内存中的程序也是一样,程序确实是程序,但不能称它为进程。我们上面学到了为更好的控制进程,我们还有PCB来描述进程。加载到内存中的程序,就是进程这个说法并不准确。我们目前可理解进程=程序文件内容+维护进程相关的数据结构。我们可结合下图理解:

————————————————


2f707fd23b794c60a4bcaed3c1b0f924.png


PCB就是操作系统给每个进程提供的。在Linux上就会自动创建出struct task_struct{} 结构体。task_struct就会包含了进程的所有属性和信息。


 有同学就会有所疑惑:操作系统到底在哪里呢?注意:操作系统也是一款软件。当我们开机时,我们相当于就是启动了操作系统这款软件,相关内容数据就会加载到了内存中。当然,操作系统也会有其对应的PCB。只不过操作系统这款软件的功能较为强大。


 当有多个进程时,操作系统就会用搞笑的数据结构将它们组织起来,以便后续的更好的管理。


 当我们知道进程中还包含了task_struct后,CPU拿数据时,是直接找程序的内容数据,还是找task_struct呢? 答案是找task_struct。我们看下图:


eea9fe25386a4b79875864e694328696.png


 如上,假如内存中有6个进程。其中每个进程的PCB都有特殊的联系,也就是操作系统见他们组织起来了。CPU拿数据时,会直接找对应进程task_struct,这样会更加高效。为什么呢?因为task_struct中包含了指向内容数据的指针,找到了进程对应的task_struct就可以找到对应的内容数据!到这里我们知道了PCB中包含了对应的内容数据指针。还有呢?


2、5 task_struct内容分类


 task_struct中包含的内容很多,在这里给大家列出主要的内容:


标示符: 描述本进程的唯一标示符,用来区别其他进程。

状态: 任务状态,退出代码,退出信号等。

优先级: 相对于其他进程的优先级。

程序计数器: 程序中即将被执行的下一条指令的地址。

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

上下文数据: 进程执行时处理器的寄存器中的数据。

I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。

其他信息。

 这里标识符下面会对齐详解。状态有运行状态,阻塞状态等等。退出码也会在下发进行详解。程序计数器也就是PC指针,该指针存储的是下条指令的地址。内存指针我们上面提到了。上下文数据和记账信息会另写一篇文章对其进行详解,因为上下文数据相对复杂,也比较重要。I/O状态信息我们可简单理解为输入输出信息状态及请求。注意:并不是你在控制I/O,也不是你所写的代码在控制I/O,而是进程在控制I/O。


2、5、1 进程标识符 PID

 进程标识符PID就是唯一标示一个进程。我们这里有一个函数getpid()可以直接返回进程的PID,如下图:7667b6395b0c4b1180c14efb4d1a317a.png

 我们可结合下面例子一起理解一下。代码如下:

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

运行结果如下图:

 当然,我们也可通过此PID找到该进程,指令为:ps ajx | grep 16940。结果如下:


096a5a00ee034ed99838d675150a1247.png

我们也可通过 kill 指令来终止该进程,指令:kill -9 16940。结果如下图:

 一个进程也是有父进程的,可通过getppid()函数获得父进程的PPID。一般在命令行上运行的命令,其父进程基本上都为bash


2、5、2 退出码

 你有没有想过,在我们所写的代码中,为什么最后都会有一句 return 0呢?return 100 可以吗?这里的 return 的数据就是我们程序结束的结束码,查看结束吗的指令为:echo $?。具体如下图:

49b2e8b313234a48be4ab6158e5c268b.png



注意,echo $? 是指的最近一次的退出码。又如下图:

三、总结


 本篇文章的内容就讲解到这里。我们来稍微总结一下:我们在讲述进程之前,是学习了冯诺依曼体系结构和操作系统管理,是我们理解起来进程更加容易。而不是突然蹦出来一个概念,显得枯燥难理解。当然,进程中还有很多细节,包括我们还没有讲解上下文数据,后面都会给大家解释。进程是一个十分重要的概念,对我们后面的学习也很重要,我们需要反复阅读,查阅资料去理解进程概念。也希望本篇文章会对你有所帮助,让你有所收获。  


相关文章
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
445 67
|
NoSQL Linux 编译器
GDB符号表概念和在Linux下获取符号表的方法
通过掌握这些关于GDB符号表的知识,你可以更好地管理和理解你的程序,希望这些知识可以帮助你更有效地进行调试工作。
546 16
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
375 16
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
254 20
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
282 0
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
346 0
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
225 0
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
286 0
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
514 4
|
Linux
Linux:守护进程(进程组、会话和守护进程)
守护进程在 Linux 系统中扮演着重要角色,通过后台执行关键任务和服务,确保系统的稳定运行。理解进程组和会话的概念,是正确创建和管理守护进程的基础。使用现代的 `systemd` 或传统的 `init.d` 方法,可以有效地管理守护进程,提升系统的可靠性和可维护性。希望本文能帮助读者深入理解并掌握 Linux 守护进程的相关知识。
735 7