【操作系统学习笔记】进程与线程(一)

简介: 注:本文为个人操作系统的学习笔记,如有错误,还请各位大神指出,谢谢!
本文首发于稀土掘金。该平台的作者 逐光而行 也是本人。

注:本文为个人操作系统的学习笔记,如有错误,还请各位大神指出,谢谢!

进程的含义?如何理解进程?

  • 进程是操作系统中最核心的概念,是对正在运行中的程序的一种抽象,本质上指的是正在运行中的程序,它拥有独立的地址空间,上面几乎存放着所有与运行这个程序有关的信息,如可执行程序,程序的数据以及程序的堆栈。
  • 进程表:与一个进程相关的所有信息,除该进程自身地址空间的内容外均放在了操作系统的一张表——进程表中。其物理结构为数组或链表,每个进程都要单独占据一项。
  • 别的角度:用某种方法把相关资源集中在一起。(因为进程有相应的独立地址空间)

关于进程模型

基于两大独立概念

资源分组处理和执行

多道程序设计:

真正的cpu在不同进程间高速来回切换,看上去就像每个进程都拥有自己虚拟的cpu。

  • 注意:在对进程编程时绝不应对时序有任何想当然的假设。
  • 如果一个程序运行了两遍,则算作两个进程。

cpu利用率=1-p^n

p表示一个进程等待I/O操作的时间与其停留在内存中时间之比

n为进程个数,也为多道程序设计的道数。

更好的模型是从 概率论(因为现实中n个进程可能同时等待IO) 和 排队论(因为单CPU中进程不是独立的) 出发构建。

进程的创建

时机(按权限大小排序)

  • 系统初始化
  • 批处理作业的初始化(见于批处理系统)
  • 正在运行的程序执行了创建进程的系统调用。
  • 用户请求创建一个新进程。

(类)UNIX系统与Windows系统的进程创建方式对比

  • UNIX系统中,fork用于创建新进程。
  • Windows系统中,(书中指win32)CreateProcess有两大作用;

    • 创建进程
    • 将正确的程序装入新的进程

图:个人对两者区别的理解
图为我个人对两者创建区别的理解(结合书中其他表述)

进程的终止

  • 自愿

    • 正常退出
    • 出错退出
  • 非自愿

    • 严重错误
    • 被其他进程杀死

UNIX和windows的进程层次结构对比

  • UNIX下,所有进程都属于以init为根的一棵。进程及其所有子进程及其后裔共同组成一个进程组。
  • windows中没有层次的概念,所有的进程地位都相同。

线程的含义?为什么需要线程?

本质上是将一个进程再细分。(因为不同进程拥有不同的地址空间和资源,一个进程的崩溃不会影响到另一个进程;而同一进程中的线程共享该进程的资源,且一个线程的崩溃会导致整个进程崩溃。这说明线程本身是进程中不可分割的一部分)

  • 正如上面所提,进程模型无法满足"使并行实体拥有共享同一个地址空间和所有可用数据"的要求,而现实中这种需求是真实而迫切的。
  • 线程比进程更轻量级,更容易(更快)创建和撤销。
  • 在多cpu系统中,多线程使得使得真正意义上的并行实现有了可能。(这里其实需要线程共享内存这一特性)

关于进程与线程

可以这么理解:进程用于把资源集中到一起,而线程则是cpu上被调度执行的实体。

关于线程的运作过程

线程的创建

进程从当前某个线程开始,该线程可通过调用一个库函数创建新的线程。

线程的优先级

有时线程间会存在父子关系,但大多数情况下,所有的线程都是平等的。

线程的退出

  • 可通过调用库函数退出,之后该线程不再可调度。
  • 调用thread_yield,允许线程自动放弃CPU从而让另一个线程运行。

(原因:线程库无法像对进程一样利用时钟中断强制线程让出CPU)

关于线程模型

  • 单个进程中的多个线程共享进程中的资源

地址空间、全局变量、打开文件集、子进程、即将发生的定时器、信号与信号处理程序、账户信息(即进程的属性)

  • 每个线程自己的内容:

程序计数器、寄存器、堆栈、状态(即线程的属性)


 为什么每个线程需要有自己的堆栈?
 因为通常每个线程会调用不同的过程,有各自不同的执行历史,所以需要堆栈来保存中间状态
  • 有两种模型:如图所示:

image.png

分别是一个进程中有一个线程,然后多进程;一个进程中有多个线程。
若线程之间关系不大,应用前者;若线程间合作密切,应用后者。

实现线程

用户态

实现方式

把整个线程包放在用户态中,内核对线程包一无所知。

  • 可以用函数库实现线程。
  • 用户空间管理进程时,每个进程需要有其专用的线程表,该表由运行时系统管理,记录各个线程的属性,并在其状态切换完成时更新启动该线程所需的信息(类比内核中的进程表存放进程信息)

优点

  • 用户级线程包可以在不支持线程的操作系统上实现。
  • 借助线程表,线程切换可以在几条指令内完成,至少比陷入内核快一个数量级。
  • 无需陷入内核、进行上下文切换、对内存高速缓存进行刷新。
  • 允许每个进程有专属的调度算法。

缺点

  • 阻塞系统调用难实现

    • 解决方案1:将系统调用全改为非阻塞的

      • 缺点:需要修改操作系统,与可在现有操作系统直接运行的初衷背离
    • 解决方案2:提前预警,并避免使用可能会引发阻塞的调用

    在系统调用周围从事检查的代码称为包装器(jacket或wrapper)

  • 缺页中断问题(原理也和阻塞调用有关)

    • 什么是缺页中断?

    简单理解就是,并非所有程序都一次性放在内存中。当程序调用或跳转到某个内存中没有存储的指令时,会发生页面故障(缺页),操作系统需要从磁盘上取回这个指令及其相关指令;在对目标指令进行定位的过程中,相关进程会被阻塞(中断当前执行程序转而去执行定位读入操作)

    • 为什么用户级线程的缺页中断需引起重视?

    因为页面故障很可能只由一个线程引起,其他线程可以正常运行。但由于内核不知道线程的存在,会将整个进程阻塞,这极大降低效率。

  • 线程的永久运行问题

线程无法像进程一样通过时钟中断实现轮换,当线程包中的一个线程开始运行时,其他线程就无法执行,这种情况有可能一直持续。(虽然线程退出机制里有thread_yield,但其是基于自愿原则)

- 可能的解决方案及其争议:让运行时系统定期请求时钟信号(中断)(可能会扰乱时钟)

  • 必要性问题

    • 用户级线程一般是为应用程序服务。多线程的目标场景是经常发生线程阻塞的应用。如果本身是CPU密集型或者少有阻塞,并不需要用到多线程。
    • 但是用户级多线程由于是在用户态,一旦发生内核陷入,原有的线程被阻塞,要借助内核的力量的话,时间开销本身也很大。

    (简单理解就是:用户级线程比较 表面 ,没出事的时候作用不大,出了事光指望它是不行的,效率还低,但是使用多线程的初衷是希望出了事能快快解决)

内核态

缺点:系统调用代价比较大。

  • 内核有用来记录系统中所有线程的 线程表。进行线程的创建或撤销时,通过一个系统调用,对线程表更新来完成。
  • 在内核中创建或撤销线程的开销大,所以会有回收线程的概念。即将撤销的线程标记不可运行的,但不改变其内部数据结构,下次可以通过改变标志位使其重新运行。
  • 内核线程不需要任何新的、非阻塞的系统调用。缺页中断问题在内核级别可得到方便解决。

内核线程无法解决所有问题

例如一个多线程进程创建新进程,新进程是该拥有单一线程,还是该复制原进程的所有线程?答案是视情况而定,调用exec是前者,继续执行当前程序是后者。

混合实现

多路复用

image.png

参考书籍

《现代操作系统》 Andrew S.Tanenbaum,Herbert Bos著,陈向群,马洪兵等译

相关文章
|
2月前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
109 1
|
1月前
|
监控 搜索推荐 开发工具
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
124 2
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
|
1月前
|
消息中间件 调度
如何区分进程、线程和协程?看这篇就够了!
本课程主要探讨操作系统中的进程、线程和协程的区别。进程是资源分配的基本单位,具有独立性和隔离性;线程是CPU调度的基本单位,轻量且共享资源,适合并发执行;协程更轻量,由程序自身调度,适合I/O密集型任务。通过学习这些概念,可以更好地理解和应用它们,以实现最优的性能和资源利用。
61 11
|
1月前
|
Java Linux 调度
硬核揭秘:线程与进程的底层原理,面试高分必备!
嘿,大家好!我是小米,29岁的技术爱好者。今天来聊聊线程和进程的区别。进程是操作系统中运行的程序实例,有独立内存空间;线程是进程内的最小执行单元,共享内存。创建进程开销大但更安全,线程轻量高效但易引发数据竞争。面试时可强调:进程是资源分配单位,线程是CPU调度单位。根据不同场景选择合适的并发模型,如高并发用线程池。希望这篇文章能帮你更好地理解并回答面试中的相关问题,祝你早日拿下心仪的offer!
37 6
|
2月前
|
C语言 开发者 内存技术
探索操作系统核心:从进程管理到内存分配
本文将深入探讨操作系统的两大核心功能——进程管理和内存分配。通过直观的代码示例,我们将了解如何在操作系统中实现这些基本功能,以及它们如何影响系统性能和稳定性。文章旨在为读者提供一个清晰的操作系统内部工作机制视角,同时强调理解和掌握这些概念对于任何软件开发人员的重要性。
|
2月前
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅,从进程管理的基本概念出发,逐步探索到内存管理的高级技巧。我们将通过实际代码示例,揭示操作系统如何高效地调度和优化资源,确保系统稳定运行。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇了解操作系统深层工作原理的大门。
|
2月前
|
存储 算法 调度
深入理解操作系统:进程调度的奥秘
在数字世界的心脏跳动着的是操作系统,它如同一个无形的指挥官,协调着每一个程序和进程。本文将揭开操作系统中进程调度的神秘面纱,带你领略时间片轮转、优先级调度等策略背后的智慧。从理论到实践,我们将一起探索如何通过代码示例来模拟简单的进程调度,从而更深刻地理解这一核心机制。准备好跟随我的步伐,一起走进操作系统的世界吧!
|
2月前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
2月前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
3天前
|
运维 自然语言处理 Ubuntu
OS Copilot-操作系统智能助手-Linux新手小白的福音
OS Copilot 是阿里云推出的一款操作系统智能助手,专为Linux新手设计,支持自然语言问答、辅助命令执行和系统运维调优等功能。通过简单的命令行操作,用户可以快速获取所需信息并执行任务,极大提升了Linux系统的使用效率。安装步骤简单,只需在阿里云服务器上运行几条命令即可完成部署。使用过程中,OS Copilot不仅能帮助查找命令,还能处理文件和复杂场景,显著节省了查找资料的时间。体验中发现,部分输出格式和偶尔出现的英文提示有待优化,但整体非常实用,特别适合Linux初学者。
39 10