进程线程剖析(二)-进程组成、状态与特点
这篇文章我们详细说下进程的组成、状态及特点。
进程线程概念全解析二 - 进程的组成、状态、特点
一、进程的组成及创建
进程的组成主要包括三大部分:PCB、程序段与数据段。程序段和数据段比较好理解,程序段就是当前正在执行的程序代码,而数据段则是在运行时动态产生的数据,比如全局变量等。我们已经知道,进程是操作系统用于实现多道程序并发执行而产生的,操作系统为了管理和控制进程的运行,需要记录一些信息,这些用于存放进程的管理和控制信息的数据结构就是 PCB(Process Control Block)。
从 PCB 的定义可以看出,它实际上是一种数据结构,而存放的是一些管理信息。主要包括如下信息:
- 进程描述信息:PID 即唯一标识进程的整形数据,每个进程对应一个 PID;UID 表示进程对应的用户ID。在 Linux 环境下,使用 ps -ef 命令,第一列展示的就是 UID,第二列则是 PID,第三列是 PPID,即父进程的 PID
- 进程控制信息:进程的状态,包括运行、就绪、阻塞等,表示进程当前的运行情况;进程的优化级等
- 资源需求相关:资源分配、控制信息等
- 其他信息:与处理机相关,各种寄存器,如程序计数器、指令寄存器等,涉及CPU上下文切换,文件描述符记录打开文件信息等
通常我们所说的创建进程,其他就是创建 PCB,而销毁进程,即销毁 PCB。一般来说,进程的创建步骤如下:
- 分配进程控制块,即 PCB 所需空间
- 初始化机器寄存器
- 初始化页表
- 将程序代码从磁盘读入内存,即读入程序段
- 将处理器状态设置为 “用户态”
- 跳转到程序的起始地址,即设置程序计数器,这一步中的中转是内核态指令。因第 5 步已经将进程设置为用户态,而用户态是不能执行内核态指令的,因此需要硬件来完成,硬件必须将第 5 步和第 6 步作为一个步骤一起来完成。
进程创建在不同的操作系统里方法也不一样。UNIX 将进程创建分为两个步骤,第 1 步是 fork,创建一个与自己完成一样的新进程;第 2 步是 exec,将新的进程的地址空间用另一个程序的内容覆盖,然后跳转到新程序的起始地址,从而完成新程序的启动。而 Winkdows 使用一个系统调用(CreateProcess)就可以完成进程创建,在调用时把要执行的程序名称作为参数传入,创建新的页表,而不需要复制别的进程。
这里进程的创建其实也可以理解为进程的复制或创建子进程。过程是一样的。下面以 Python 代码为例,实现创建进程:
import os
print(f'Main Process ({os.getpid()}) start...')
pid = os.fork()
if pid==0:
print(f'I am child process ({os.getpid()}) and my parent is {os.getppid()}.')
else:
print(f'I ({os.getpid()}) just created a child process ({pid}).')
# 运行结果,运行时 pid 数值可能不一样
# Main Process (15174) start...
# I (15174) just created a child process (15175).
# I am child process (15175) and my parent is 15174.
二、进程的状态
进程一般分为三种状态:就绪、阻塞和运行。在 3 种状态之间可以进行转换,但并不是两两状态均可以转换的,可以转换的有如下几种:
- 就绪态 -> 执行态
- 执行态 -> 就绪态,即可能时间片执行完毕进行进程切换,处理机选择另一个进程执行,则当前进程由执行态转换为就绪态
- 执行态 -> 阻塞态,即进程因某等待某些操作完成,如IO,由执行转换为就绪
- 阻塞态 -> 就绪态,当进程等待的操作完成后,由阻塞转换为就绪。这里需要注意的是,操作系统并不会从阻塞队列里挑选可执行的进程,因此进程并不能直接从阻塞态转换为执行态
这三种状态是比较典型的进程状态分类方式,但并不是唯一的分类方式,许多商业操作系统的进程状态不止 3 个。不管如何做分类,其目的都是便于操作系统管理进程。是否细分的唯一依据就是是否对管理有利。
三、进程的特点
进程,表示是当前正在运行的进程实体(也可以理解为程序代码),“正在运行”体现了进程一个很重要的特征,那就是动态性。
其次,我们都知道多进程并发,一个时间段是允许多个程序并发执行的,所以进程还具有并发性。
另外,每个进程都有独立的 PCB 来管理相关信息,所以每个进程都是独立的个体,且是有有结构的个体。即独立性与结构性。
最后,进程在并发执行时,每个进程是独立的,以不可预知的顺序和速度向前推进的,因此还具有异步性,这也引出在某些情况下需要使用进程同步机制来解决异步带来的问题。
四、总结
本小节介绍了进程组成相关知识点,我们需要知道:
- 进程是由操作系统管理的
- 进程主要由 PCB、数据段、程序段组成。其中 PCB 是一种数据结构,为操作系统管理进程提供信息
- 进程状态的切换,不同操作系统对进程状态细分程序不一样
- 进程具有动态性、并发性、结构性、独立性、异步性等特点
- Mac OS平台下应用程序安装包制作工具Packages的使用介绍
- 协议森林02 小喇叭开始广播 (以太网与WiFi协议)
- 信号与频谱
- Mac OS平台下应用程序安装包制作工具Packages的使用介绍(补充)
- 数字按照不同格式转换成字符串
- macOS下加载动态库dylib报"code signature invalid"错误的解决办法
- Asp.net管道模型(管线模型)之一发不可收拾
- Python深入01 特殊方法与多范式
- MacOS平台下@rpath在动态链接库中的应用
- Python深入02 上下文管理器
- 剑指OFFER之字符串的排列(九度OJ1369)
- 高性能计算机传奇
- ffmpeg编解码视频导致噪声增大的一种解决方法
- 剑指OFFER之二叉搜索树与双向链表(九度OJ1503)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- CVE-2020-14644 weblogic iiop反序列化漏洞
- Ubuntu 17.10 安装折腾记录
- charles工具使用
- 干货 | 从0到1,搭建一个体系完善的前端React组件库
- LeetCode 01两数之和&02两数相加
- 给GitHub "彩蛋" readme 生成自定义统计信息
- Android |《看完不忘系列》之okhttp
- pt-osc改表过程中的中文乱码问题
- Hive Query生命周期 —— 钩子(Hook)函数篇
- python快速排序
- 扩展 Microsoft.Owin.Security
- Angular 2 版本的 ng-bootstrap 初体验
- 揭开MySQL“锁”的神秘面纱
- 从0到1开发测试平台(九)后端对接口response的封装
- 在 Mac OS X 上安装和配置 Wine