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

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

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

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

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

关于进程模型

基于两大独立概念

资源分组处理和执行

多道程序设计:

真正的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著,陈向群,马洪兵等译

相关文章
|
12天前
|
算法 调度 UED
深入理解操作系统:进程调度与优先级队列
【10月更文挑战第31天】在计算机科学的广阔天地中,操作系统扮演着枢纽的角色,它不仅管理着硬件资源,还为应用程序提供了运行的环境。本文将深入浅出地探讨操作系统的核心概念之一——进程调度,以及如何通过优先级队列来优化资源分配。我们将从基础理论出发,逐步过渡到实际应用,最终以代码示例巩固知识点,旨在为读者揭开操作系统高效管理的神秘面纱。
|
6天前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
5天前
|
消息中间件 安全 算法
深入理解操作系统:进程管理的艺术
【10月更文挑战第38天】在数字世界的心脏,操作系统扮演着至关重要的角色。它不仅是硬件与软件的桥梁,更是维持计算机运行秩序的守夜人。本文将带你走进操作系统的核心——进程管理,探索它是如何协调和优化资源的使用,确保系统的稳定与高效。我们将从进程的基本概念出发,逐步深入到进程调度、同步与通信,最后探讨进程安全的重要性。通过这篇文章,你将获得对操作系统进程管理的全新认识,为你的计算机科学之旅增添一份深刻的理解。
|
9天前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第34天】本文旨在探讨操作系统中至关重要的一环——进程管理及其调度策略。我们将从基础概念入手,逐步揭示进程的生命周期、状态转换以及调度算法的核心原理。文章将通过浅显易懂的语言和具体实例,引导读者理解操作系统如何高效地管理和调度进程,保证系统资源的合理分配和利用。无论你是初学者还是有一定经验的开发者,这篇文章都能为你提供新的视角和深入的理解。
31 3
|
11天前
|
Linux 调度 C语言
深入理解操作系统:进程和线程的管理
【10月更文挑战第32天】本文旨在通过浅显易懂的语言和实际代码示例,带领读者探索操作系统中进程与线程的奥秘。我们将从基础知识出发,逐步深入到它们在操作系统中的实现和管理机制,最终通过实践加深对这一核心概念的理解。无论你是编程新手还是希望复习相关知识的资深开发者,这篇文章都将为你提供有价值的见解。
|
8天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
19 1
|
12天前
|
算法 调度 UED
深入理解操作系统的进程调度机制
本文旨在探讨操作系统中至关重要的组成部分之一——进程调度机制。通过详细解析进程调度的概念、目的、类型以及实现方式,本文为读者提供了一个全面了解操作系统如何高效管理进程资源的视角。此外,文章还简要介绍了几种常见的进程调度算法,并分析了它们的优缺点,旨在帮助读者更好地理解操作系统内部的复杂性及其对系统性能的影响。
|
10天前
|
消息中间件 算法 调度
深入理解操作系统:进程管理的艺术
【10月更文挑战第33天】本文旨在揭示操作系统中进程管理的神秘面纱,带领读者从理论到实践,探索进程调度、同步以及通信的精妙之处。通过深入浅出的解释和直观的代码示例,我们将一起踏上这场技术之旅,解锁进程管理的秘密。
17 0
|
12天前
|
算法 Linux 调度
深入理解操作系统之进程调度
【10月更文挑战第31天】在操作系统的心脏跳动中,进程调度扮演着关键角色。本文将深入浅出地探讨进程调度的机制和策略,通过比喻和实例让读者轻松理解这一复杂主题。我们将一起探索不同类型的调度算法,并了解它们如何影响系统性能和用户体验。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇理解操作系统深层工作机制的大门。
23 0
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程

热门文章

最新文章