前言:操作系统简介
概念
设计目的
理解
进程:程序的执行之魂
进程和程序的联系与区别
描述进程-PCB
进程的标识符
进程状态
状态转换
僵尸进程
孤儿进程
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
狭义上来说,操作系统只是操作系统的内核。
具体来说,有以下几个目的:
在整个计算机软硬件架构中,操作系统的定位是:一款专门用于“管理”的软件 。
怎么理解这个“管理”?
总的来说就是:
那么操作系统对进程的管理就是先把进程描述起来,再把进程组织起来!
进程,简而言之,是程序在计算机中的一次执行实例,是系统资源(如CPU时间、内存)的分配实体。Linux中,进程以task_struct
(进程控制块,PCB)的化身形式存在内存中,存储着进程的全息:标识符、状态、优先级、程序计数器、内存指针、I/O状态、记账信息等。每一个进程,皆是task_struct
链表的一员,是Linux内核管理进程的基石。
基本概念
主要区别:
- 静态与动态:
- 程序是静态的,它是一组指令的集合,本身不具有执行的能力。
- 进程是动态的,它是程序在执行过程中的一个实例,包含了程序运行的当前状态。
- 生命期:
- 程序的存在是永久的,只要不被删除或修改,它将一直存在于存储介质中。
- 进程则是有生命的,它因创建而产生,因调度而执行,因得不到资源而暂停,因撤销而消亡。
- 组成:
- 程序仅包含指令的集合,不包含执行时的数据状态。
- 进程则是由程序、数据和进程控制块(PCB)三部分组成。PCB是进程存在的唯一标识,包含了进程的状态信息、控制信息以及资源分配情况等。
- 对应关系:
- 同一程序可以对应多个进程。当程序被多次执行时,每次执行都会创建一个新的进程。
- 但一个进程只能对应一个程序(虽然一个进程可以执行多个程序段,但通常指其主程序)。
- 独立性:
- 程序作为指令的集合,其本身是独立的,不依赖于特定的执行环境。
- 进程则是一个独立的执行实体,具有独立的内存空间和系统资源,可以与其他进程并发执行。
联系:进程是程序的一次执行过程,是程序动态特性的体现。没有程序就没有进程可言;而进程则是程序在特定数据集合上的具体执行实例,是程序功能得以实现的载体。
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
- 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct。
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
task_struct的内容分类
在Linux中,进程 = 内核task_struct结构体 + 程序的代码和数据。
概念:
- 进程的标识符(PID,Process Identifier)是系统给每个进程定义的一个唯一标识该进程的非负整数。这个标识符类似于人的身份证号码,用于唯一地识别和定位一个进程。
- 其类型为 pid_t(整型),其本质上是一个无符号整型的类型别名(typedef),范围:0~32767。
特性:
- 唯一性:每个进程在系统中都有一个唯一的进程标识符,不同进程的标识符不会重复。
- 动态性:当一个进程结束时,其标识符可以被系统回收并重新分配给新的进程。
注:在某些系统中,特定的进程标识符被保留给特定的系统进程。例如,进程标识符0通常被保留给系统调度进程(如Linux中的swapper进程),而进程标识符1则通常被分配给系统初始化进程(如Linux中的init进程)。
进程id (pid): 标识进程的一个非负整型数。
父进程id (ppid) : 任何进程( 除 init 进程)都是由另一个进程创建,该进程称为被创建进程的父进程,对应的进程id称为父进程id(PPID)。如,A 进程创建了 B 进程,A 的进程号就是 B 进程的父进程id。
获取进程id和查看进程
getpid函数(获取进程id)
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
getppid函数(获取父进程id)
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
查看进程 : ps ajx
我们可以先看看Linux内核源代码是怎么描述进程(任务)的状态的:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
五态模型:
- 新建态(创建状态):
- 进程被创建时的初始状态。在这一状态下,系统为进程分配必要的资源,并进行初始化操作。
- 当操作系统完成了进程创建的必要操作,并且当前系统的性能和内存的容量均允许时,进程将进入就绪态。
- 就绪态:
- 进程已处于准备好执行的状态,即进程已分配到除CPU以外的所有必要资源后,只要再获得CPU,便可立即执行。
- 在这一状态下,进程已经具备了执行条件,但尚未被调度到CPU上执行。
- 运行态(执行状态):
- 进程已获得处理机(CPU),其程序正在处理机上执行。
- 在这一状态下,进程占用CPU资源,执行程序代码,实现进程的功能。
- 阻塞态(等待状态):
- 正在执行的进程由于发生某事件(如I/O请求、申请缓冲区失败等)而暂时无法执行,即指进程的执行受到了阻塞。
- 在这一状态下,进程无法继续执行,需要等待外部事件或资源的满足。
- 终止态(结束状态):
- 进程执行完毕或被系统终止时的状态。在这一状态下,系统需要进行善后处理,如释放进程占用的资源等。
僵尸进程的危害
僵尸进程本身不占用系统资源(除了进程表中的一个槽位),但它们会积累并占用越来越多的进程表条目,特别是如果父进程频繁地创建子进程而不回收它们时。在进程数量有限制的系统中(比如某些UNIX系统),这可能会导致无法再创建新的进程。
简单来说,就是会造成内存泄漏。
____________________
⭐感谢你的阅读,希望本文能够对你有所帮助。如果你喜欢我的内容,记得点赞关注收藏我的博客,我会继续分享更多的内容。⭐