进程

介绍进程相关原理和实现

进程

进程的概念

进程与程序

  • 一个操作系统可以运行许多个程序,一个运行中的程序被称为进程(Process)
  • 进程与程序的关系:
    • 程序是被动和静态的,进程是主动和动态的
    • 一个程序对应的可能有多个进程
    • 程序可以通过GUI或命令行启动

进程的组成

  • 程序代码
    • 内容:可执行的程序指令
    • 特点:只读,多个相同进程可以共享同一份代码
  • 运行时CPU状态
    • 程序技术去(PC): 指向下一条要执行的指令地址
    • 寄存器组:
      • 通用寄存器:存储计算数据
      • 状态寄存器:保存处理器状态标志
      • 专用寄存器:如栈指针、基址寄存器等
  • 内存区域
    • 栈(Stack)
    • 数据段(Data Section)
    • 堆(Heap)

进程的状态(State)

  • 一个进程包含以下状态
    • new
    • running
    • wating/blocking
    • ready
    • terminated
  • 状态转换示意图

State

进程控制块(Process Control Block, PCB)

基本概念

  • PCB是操作系统管理进程的核心数据结构,每个进程都有唯一的PCB

PCB的四大类信息、

  • 进程标识信息
    • PID:进程唯一标识符
    • PPID:父进程ID
    • UID/GID:用户和组标识符
  • 处理机状态信息
    • 程序计数器(PC):下一条指令地址
    • 寄存器组:CPU寄存器的值
    • 栈指针:当前栈位置
  • 进程调度信息:
    • 优先级:调度优先级
    • 进程状态:运行/就绪/阻塞等
    • CPU时间:已使用和分配的时间
  • 进程控制信息
    • 内存管理:页表、内存映射
    • 文件管理:打开的文件列表
    • 信号处理:信号处理机制

PCB的关键作用

  • 上下文切换
    • 保存当前进程状态到PCB,然后从PCB恢复目标进程状态
  • 进程管理
    • 创建:分配新PCB
    • 调度:基于PCB信息选择进程
    • 终止:释放PCB和相关资源
  • 资源跟踪
    • 内存分配情况
    • 打开的文件
    • 拥有的设备

PCB在linux中的实现: task_struct

  • Linux使用task_struct结构体实现PCB,包含:
    • 进程状态和标识
    • 内存管理信息(mm_struct)
    • 文件系统信息(files_struct)
    • 父子进程关系
  • PCB在系统中的组织
    • 进程链表:所有进程形成链表
    • 哈希表:通过PID快速查找
    • 运行队列:就绪进程的调度队列

线程(Thread)

进程调度

调度

  • CPU调度器会选择接下来要运行的进程并分配内存。这个操作一般是非常快的

调度队列

定义

  • 操作系统内核用来组织和管理不同状态进程的数据结构,是实现搞笑进程调度的基础。

三种主要调度队列

  • 作业队列(Job Queue)
    • 范围:系统中的所有进程
    • 用途:全局管理和统计
    • 对应命令:ps aux
  • 就绪队列(Ready Queue)
    • 范围:准备执行的进程
    • 特点:按优先级组织,支持快速选择
    • 实现:多级队列 + 位图索引
  • 设备队列(Device Queue)
    • 范围:等待I/O的进程
    • 分类:磁盘、网络、键盘等不同设备
    • 状态:TASK_INTERRUPTIBLE/UNINTERRUPTIBLE

上下文切换(Context Switch)

定义

  • 内核切换到另一个进程去执行,保存就进程的状态并加载新进程的已保存状态

开销

  • 上下文切换是开销,CPU在切换时不做任何有用的工作。操作系统和PCB越复杂,上下文切换时间越长,时间取决于硬件支持。某些硬件为每个CPU提供多组寄存器,可以同时加载多个上下文

进程创建

概念

  • 父进程可以创建子进程,子进程可以进一步创建子进程,形成进程树。进程通过进程标识符(PID)来识别和管理

Design choices

  • 三种可能的资源共享级别:全部、子集、无
  • 父进程和子进程的地址空间管理
    • 子进程复制父进程地址空间(Linux)
    • 子进程加载新程序(Windows)
  • 父进程和子进程的执行
    • 父进程和子进程并发执行
    • 父进程等待子进程终止

用于进程创建的系统调用

  • fork: 创建一个新的进程副本,结束时会返回
  • exec: 使用一个新的进程的地址覆盖当前进程地址,加载了新程序,不会返回原程序
  • wait: 阻塞直到子进程结束

进程终止

工作流程

  • 正常终止:进程执行最后一条语句并请求内核删除它(exit)
    • 操作系统将子进程的返回值传递给父进程(wait)
    • 进程的资源被操作系统释放
  • 异常终止:父进程可能终止子进程的执行(abort)
    • 子进程超出了分配到的资源
    • 分配给子进程的任务不在被需要
    • 如果父进程退出,一些操作系统不允许子进程继续
      • 所有子进程(整个子树)将被终止-这被称为级联终止(cascading termination)

注:exit与_exit

  • exit为标准库函数,执行终止进程和清理
  • _exit为系统调用,直接请求内核终止进程,不做清理

可能存在的错误————僵尸进程与孤儿进程

僵尸进程
  • 僵尸进程时已经执行完毕但父进程还没有回收其退出状态的子进程
  • 特征
    • 进程已死亡:不再执行任何代码
    • PCB仍存在:内核保留进程控制块
    • 保存退出状态:等待父进程读取
    • 不占用内存:代码段、数据段、栈都释放
    • 占用PID槽位:PID不能被其他进程使用
    • ps显示为<defunct>:状态标记为Z
孤儿进程
  • 孤儿进程是父进程已经退出,但子进程仍然在运行的进程
  • 特征
    • 仍在运行:进程仍然正常执行
    • 父进程变更:PPID变为1(init进程)
    • 正常运行:功能不受影响
    • 自动回收:退出时由init进程回收
    • 通常无害:不会造成资源泄漏
关键区别
  • 僵尸进程是管理问题,有害,大量积累会耗尽系统资源,需要程序员解决
  • 孤儿进程是自然现象,无害,系统自动解决

Android进程

Android进程重要性层次结构

  • 移动操作系统经常需要终止进程来回收系统资源(如内存)。按重要性从高到低排列
    • 前台进程:在屏幕上可见
      • 用户正在使用微信
    • 可见进程:不直接可见,但执行前台进程正在引用的活动
      • 视频应用播放时弹出权限对话框
    • 服务进程:如流媒体音乐
      • 音乐应用后台播放
    • 后台进程:执行活动,但用户不明显感知
      • 用户切换应用后原应用进入后台
    • 空进程:不包含任何活动
  • Android将开始终止最不重要的进程

浏览器的多进程架构

  • 在过去许多网页浏览器作为单一进程运行(有些仍然如此)。这会导致如果一个网站出现问题,整个浏览器都可能挂起或崩溃
  • Google Chrome浏览器采用多进程架构,包含3中不同类型的进程:
    • 浏览器进程:管理用户界面、磁盘和网络I/O
    • 渲染进程:渲染网页,处理HTML、Javascript。为每个打开的网页创建新的渲染进程
    • 运行在沙箱中,限制磁盘和网络I/O,最小化安全漏洞的影响
    • 插件进程:为每种类型的插件创建进程

进程间通信

概念

  • 系统中的进程可能是独立的或协作的
    • 独立进程:无法影响或被其他进程的执行所影响的进程
    • 协作进程:可以影响或被其他进程影响的进程,包括共享数据
  • 协作进程的原因:信息共享、计算加速、模块化、便利性、安全性
  • 写作进程需要进程间通信(IPC)

IPC模型

  • 存在两种IPC模型:
    • 共享内存
    • 消息传递
  • 示意图:

    IPC

生产者-消费者问题

  • 协作进程的范例,生产者进程产生信息,被消费者进程消费
  • 无界缓冲区:对缓冲区大小没有实际限制
  • 有界缓冲区:假设有固定的缓冲区大小

消息传递

  • 进程通过交换消息互相通信
  • 无需依赖共享变量
  • 消息传递提供两个操作
    • send:发送消息
    • receive:接受消息
  • 如果P和Q希望通信,它们需要
    • 在它们之间建立通信链路
    • 例如:邮箱(间接)或基于pid(直接)
    • 通过send/receive交换消息
  • 直接与间接通信
    • 直接通信
      • 对称寻址: send(P, Message), receive(Q, Message)
      • 非对称寻址: send(P, message), receive(id, Message)
    • 间接通信
      • send(A, Message), receive(A, Message) -邮箱A
      • 邮箱可以由进程和操作系统实现
      • 邮箱所有者:谁可以接收消息
  • 同步机制
    • 消息传递可以是阻塞的或非阻塞的
    • 阻塞被认为是同步的
      • 阻塞发送:发送者阻塞直到消息被接收
      • 阻塞接收:接收者阻塞直到有消息可用
    • 非阻塞被认为是异步的
      • 非阻塞发送:发送者发送消息后继续执行
      • 非阻塞接收:接收者接收有效消息或返回空值
  • 缓冲机制
    • 附加到链路的消息队列
    • 零容量:0条消息
      • 发送者必须等待接收者
    • 有些容量:有线长度的n条消息
      • 如果链路满,发送者必须等待
    • 误解容量:无限长度
      • 发送者永不等待

POSIX共享内存

概念

  • 进程首先创建共享内存段
  • 也用于打开现有的内存段
  • 设置对象的大小
  • 使用mmap()将文件指针内存映射到共享内存对象
  • 对共享内存的督学通过mmap()返回的指针完成

管道

  • 管道作为一个通道,允许两个本地进程通信
  • 关键问题
    • 通信是单向的还是双向的?
    • 在双向通信的情况下,是半双工还是全双工?
    • 进程之间是否必须存在关系(即父子关系)?
    • 管道是否可以在网络上使用?
    • 通常只用于本地进程
  • 普通管道
    • 普通管道允许生产者-消费者风格的通信
    • 生产者写入一端
    • 消费者从另一端读取
    • 因此普通管道是单向的
    • 如果需要双向通信,需要两个管道
    • 要求通信进程之间有父子关系
  • 命名管道
    • 命名管道比普通管道更强大
    • 通信是双向的
    • 进程之间不需要父子关系
    • 多个进程可以使用命名管道进行通信
    • 命名管道在UNIX和Windows系统上都有提供
    • 在Linux上,它被称为FIFO

客户端-用户交互

套接字(Socket)

  • 套接字被定义为通信的端点
  • IP地址和端口的连接
  • 套接字 161.25.19.8:1625 指的是主机 161.25.19.8 上的端口 1625
  • 通信在一对套接字之间进行
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计