哈工大操作系统学习笔记(二)进程与线程

news2025/1/12 7:45:18

文章目录

  • CPU管理的直观想法
  • 多进程图像
  • 用户级线程
  • 内核级线程
  • 内核级线程实现
  • 操作系统之树
  • CPU 调度策略
  • 一个实际的schedule 函数
  • 进程同步与信号量
  • 信号量临界区保护
  • 信号量的代码实现
  • 死锁处理

CPU管理的直观想法

  • CPU的工作原理: 自动的取值执行,给了初始地址,之后CPU就自动取值执行
  • IO 指令非常慢,但是计算指令非常快
  • 提出问题,假设多条计算指令和 一条IO指令 形成 一段代码,当顺序执行的时候,运行到IO指令,需要大量的时间操作磁盘,这个时候CPU会做什么?是直接等待还是做什么操作?
  • 答案是 当运行到 IO操作的时候,CPU会切出去做其他操作,当 IO操作完成之后,发出中断,CPU又会返回接着做剩下的操作,这样的操作可以大大提升CPU的利用率
  • 由此可见CPU是 多道程序 交替执行,下面举个例子

在这里插入图片描述

  • 单道程序只能顺序执行,所以CPU完成两个作业的时间是80
  • 多道程序是两个作业交替执行,当操作第三方设备时,CPU可以执行别的作业,当两个作业都需要CPU时,只能顺序执行,所以多道程序完成两个作业的时间是45
  • 由此可见CPU多道程序的利用率非常高
  • 当多个程序运行时,CPU如何进行并发操作呢?
  • 答案是 多个程序同时运行,不过当CPU运行程序1 n个时间 的时候,又去运行程序2 n个时间,这样就是并发操作
  • 但是还有个问题,CPU运行程序1 跳到 程序2的时候,如何记录运行到哪个指令,这个时候就需要一个记录数据结构PCB来记录。
  • 由此可见,运行的程序跟静态的程序是有一定区别的,还是需要一定的包装,所以这个时候就引入一个新的概念,进程,进程就是进行中的程序

多进程图像

  • 用户操作操作系统,本质就是操作多个进程
  • 进程的顺序:
    • 启动操作系统
    • 在main函数中 fork() 创建第一个进程 if(!fork()) {init();} Shell ( windows桌面 )
    • shell()进程里面就可以接着启动其他进程,进程完成后,返回Shell()进程
      在这里插入图片描述
  • 多进程如何组织?
    • 核心就是 Process Control Block 结构,用来记录进程信息的数据结构
      在这里插入图片描述
    • 多进程有哪些状态?:
      • 就绪态:就绪态 -》运行态
      • 运行态:运行态 -》 阻塞态,运行态 -》就绪态
      • 阻塞态:阻塞态 -》 就绪态
        在这里插入图片描述
    • 多进程如何切换?看下面的例子在这里插入图片描述
    • 多进程调度的优先级又是怎么样的?
      • FIFO :先到先得
      • Priority:设定优先级,优先级高的优先
    • 多进程具体是如何切换?看下面的代码,将进程的信息进行切换
      在这里插入图片描述
    • 但是多个线程在内存中,会存在对同一块资源进行操作的问题,怎么样才能保证资源操作之后准确性的问题呢?
      • 限制对一块资源的读写
    • 多进程如何进行合作呢?
      • 生产者-消费者实例
        在这里插入图片描述
        在这里插入图片描述
      • 上面是消费者和生产者的运行过程,但是会有问题,下列的问题
        在这里插入图片描述
      • 正常来说 counter应该是5 但是最后得出是4,显然是不对的,所以这时候就需要多进程同步了,合理推进多进程的顺序。
        在这里插入图片描述

用户级线程

  • 上一节说到进程切换,这一节我们需要讲解线程,首先来想一个问题,如果进程之间只是一个函数进行切换,然后就需要动用太多资源的切换是不是不太值得,有没有可能用一个更小的单位去切换,代价会小一点。
  • 所以这个时候就引出了线程的概念,保留了并发的优点,避免了进程切换的代价
  • 线程切换,只是指令之间的切换,并不涉及共享资源的之间的切换
  • 下面举个例子,来说明如何进行线程之间的切换:GetData线程 和 Show线程
    在这里插入图片描述
    • 其中切换的方法就是 yield 方法,所以线程切换最核心的部分就是 yield
    • 下面就是切换举例:
      在这里插入图片描述
      • 首先执行 A 函数,运行到 B 函数的时候,需要将原本的位置保存起来,就是将 104 放到栈中
      • 然后开始执行 B 函数,运行到 yield 函数 又要进行跳转,所以将 204 也放到栈中
      • 这个时候已经切换到 C 函数,C 函数继续执行,又调用了 D 函数,所以将 304 放到栈中
      • 然后开始执行 D 函数,D 函数执行使用 yield 函数,又跳转到 B 函数,所以将 404 放到栈中
      • 然后继续执行 B 函数,B 函数执行完之后 ,就会 调用 ret 函数,对应的栈就会弹栈,而栈中的 404 就会弹出,这个时候就不对劲,为什么是 404 弹出呢? 明显不对,但是又怎么解决呢?
      • 补充:
        在这里插入图片描述
      • 很显然 A 和 B 函数应该是一个进程 ,C 和 D 函数应该是另一个进程,所以如果两个进程的线程都公用一个栈的话,就会出现刚才的问题,ret 指令 之后,会从另一个进程开始执行
      • 解决方案:一个执行序列 就 拥有自己独立的栈,使用TCB 和 栈 相互配合
        在这里插入图片描述
        • 现在重写了yield 函数,将两个指令序列之前的跳转隔离开,但是有个问题,按照上图执行的效果,204是弹不了栈的,因为 执行到 jmp 204 的时候,就会跳转,所以 204 永远不会弹出来。但如果把 jmp 204 删除呢?括号之后就会执行 ret 指令 ,并且现在的栈是 TCB1的栈,204 是可以弹出的,然后 执行会顺着 204 的位置继续执行。
          在这里插入图片描述
      • ThreadCreate 函数:创建 线程 的必须品
        • malloc :申请一段内存用来给TCB
    • 整个流程:
      在这里插入图片描述
  • 什么是用户级线程?
    在这里插入图片描述

内核级线程

  • 用户级线程与内核级线程的区别:
    • 用户级线程用的是两个栈,内核级线程是两套栈
  • 用户栈和内核栈之间的关联:
    • 内核栈中的ss和sp都存着用户栈中的指令地址,所以int的时候进入内核栈,iret就弹出返回用户栈
      在这里插入图片描述
  • 下面举个例子:
    在这里插入图片描述
    在这里插入图片描述
    • switch_to :仍然是通过TCB找到内核栈指针,然后通过ret切到某个内核程序,最后再用cs : pc 切到用户程序
  • 各个线程对比:
    在这里插入图片描述

内核级线程实现

在这里插入图片描述

  • 故事从一个代码开始
    在这里插入图片描述
  • A 方法 运行到 fork() 的时候,就会压栈,把对应的地址压倒内核栈中,然后等 INT 0X80 指令结束后,就会通过内核栈中的地址返回用户栈对应的位置
    在这里插入图片描述
  • 另一个故事

操作系统之树

  • 通过实现一个功能,再整体看看如何设计操作系统程序,实现在页面上打印ABABBBBAAA等数据
  1. 第一步从用户代码开始,首先执行 fork()函数创一个子进程A
    在这里插入图片描述
  2. 用汇编的语言转换就变成下面那样在这里插入图片描述
  3. 通过 int 0X80 进入到内核
    在这里插入图片描述
    • 然后执行 system_call ,然后执行 sys_fork 在这里插入图片描述
    • 一直运行,然后执行 coy_process ,在内核中做一个子进程
      • 做出一个新的PCB
      • 做出一个新的栈在这里插入图片描述
    • 执行完 copy_process 就要开始执行 ret 开始回退了在这里插入图片描述
  4. 继续执行代码,发现又有一个 fork()函数(创建一个子函数),再一次产生一个子进程B(一个PCB + 内核栈)
    在这里插入图片描述
  5. 然后父进程继续执行,执行wait()函数,等待
    • 将父进程状态置为等待
    • 父进程阻塞
      在这里插入图片描述
  6. 然后父进程就要执行 schedule()函数,选择子进程函数,通过运行 switch_to() 函数 进行切换
    在这里插入图片描述
  7. switch_to 切换 到 A
    • 把 CPU 的内容,放置到 父进程的 tss 上
    • 把 子进程 A 的 tss 内容,放置到 cpu 上
      在这里插入图片描述
    • 开始执行 子进程A
      在这里插入图片描述
  8. 这个时候有个问题,就是屏幕上只会打印A ,不会打印B ,因为子进程没有切换程序,那怎么样才能切换的呢?
    • 这时候就需要时钟中断,每次一到时钟中断就切换到B
      在这里插入图片描述
      在这里插入图片描述
  9. 这样就会完成 屏幕上交替 执行 A 和 B

CPU 调度策略

  • CPU 调度是如何调度的呢?,先看下面的例子
    在这里插入图片描述
  • CPU 调度最直观的想法 就是 就绪队列中有很多进程究竟选择谁来执行呢
  • CPU 调度有两种思想:
    • FIFO :先到先执行
    • Priority :选择优先权大的,先执行
  • 面对诸多场景,如何设计调度算法?
  • 就是需要让进程满意,如何让进程满意呢?
    • 尽快结束任务:周转时间(从任务进入到任务结束)少
    • 用户操作尽快响应:响应时间短
    • 系统内耗时间少:吞吐量
  • 但是想要完成上面那几点需要考虑的因素有很多在这里插入图片描述
  • 第一种CPU 的 调度算法:FCFS 先来先服务
    在这里插入图片描述
    • 但是第一种方式 周转时间太高了,假设 将 P3这种短作业的提前,周转时间就会变小,所以这样就引出了优化的 调度算法:SJF 短作业优先在这里插入图片描述
  • 第二种CPU 的 调度算法: 用时间片来轮转调度
    • 每一定时间片运行一个任务,到了时间就切换
      在这里插入图片描述

一个实际的schedule 函数

  • 操作系统的调度函数
    • 第一个if 的目的就是 找到最大的 counter 的进程,这就是典型的优先级算法
    • 第二个 for 的 目的,就是把阻塞IO的线程优先级提高
      在这里插入图片描述
  • Counter的作用:时间片
    在这里插入图片描述
  • counter 的另一个作用:优先级
    在这里插入图片描述
  • counter 总结:
    在这里插入图片描述

进程同步与信号量

  • 如何使得多个进程执行的合理有序?
  • 例子:多个进程共同完成一个任务
    • 实例1 : 司机操作完之后,会给一个信号给售票员,售票员收到之后,开始执行操作,执行完一个操作,也发送一个信号给司机,则司机执行下一个操作,通过这个例子可以看出,进程之间执行合理可以通过相对应的信号来沟通
      在这里插入图片描述
  • 生产者-消费者实例
    在这里插入图片描述
  • 当生产者把缓冲区占满了之后,就要通知消费者开始消费缓冲区的数据
    在这里插入图片描述
  • 但是光通知还不够,还需要让生产者不再往缓冲区里面添加数据,这个时候就需要暂停生产者进程
    在这里插入图片描述
  • 但是只发送信号,还不能解决全部问题,因为信号量太少了,所以还需要更加丰富的信号量来解决
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
  • 通过信号量解决生产者 - 消费者问题
    • empty 信号量 是缓冲区
    • mutex 信号量 是文件是否有人再操作
      在这里插入图片描述

信号量临界区保护

  1. 如果不对信号量进行保护,多个进程进行操作,就有可能发生错误
  2. 所以这种问题得主要是竞争关系
    在这里插入图片描述
  3. 而解决这个竞争条件最直观的想法是给共享资源在写操作的时候上锁
    在这里插入图片描述
  4. 临界区:一次只允许一个进程进入得该进程的那一段代码
    在这里插入图片描述
  5. 临界区代码的保护原则:
    • 互斥性:当一个进程在临界区执行,则其他进程不允许进入
      在这里插入图片描述
  6. 临界区代码保护方法:轮换法
    • 进程轮流进去
    • 满足互斥性
    • 问题:如果P0 执行完临界区了以后,turn=1了,但是P1 不执行临界区,所以turn不会等于0,就会导致p0一直是用不了
      在这里插入图片描述
  7. 临界区代码保护方法:标记法
    * 由轮换法导致问题,我们想到一个新的方法,就是标记法,就是假设P0进程想进去临界区,设置他的状态为True,并且判断P1是否也想进入临界区,如果执行完临界区的代码,则把状态变成fals
    * 问题:P0进程判断的时候获取的P1的状态的时候有延迟,则两边都过不去
    在这里插入图片描述
  8. 临界区代码保护方法:非对称标记法
    • 结合标记和轮转的思想
      在这里插入图片描述
      在这里插入图片描述
  9. 临界区代码保护方法:面包店算法
    在这里插入图片描述

信号量的代码实现

  • 对于信号量的代码实现:
    在这里插入图片描述
    在这里插入图片描述

死锁处理

  • 生产者和消费者会因为信号量的争夺产生死锁
  • 实例
    在这里插入图片描述
  • 假设调换位置
    在这里插入图片描述
  • 这样会形成环路,所以我们将这种多个进程由于互相等待对方持有的资源而造成的谁都无法执行的情况叫死锁
  • 死锁的4个必要条件:
    • 互斥使用
    • 不可抢占
    • 请求和保持
    • 循环等待
  • 死锁的处理方法:
    • 死锁预防:破坏死锁出现的条件
    • 死锁避免:检测每个资源请求,如果造成死锁就拒绝
    • 死锁检测+恢复:检测到死锁出现时,让一些进程回滚,让出资源
    • 死锁忽略:就好像没有出现死锁一样
  • 银行家算法:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193503.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Swift 周报 第二十一期

前言 本期是 Swift 编辑组自主整理周报的第十二期,每个模块已初步成型。各位读者如果有好的提议,欢迎在文末留言。 Swift 周报在 GitHub 开源,欢迎提交 issue,投稿或推荐内容。目前计划每两周周一发布,欢迎志同道合的…

永久删除的照片怎么找回来?教你三招恢复方法

如果文件被永久删除了,想要恢复就没有这么简单了,永久删除的文件可能是已经从回收站清空的文件,或者是我们按住快捷键“shiftdelete”快捷键删除的文件,这样的话,我们无法在电脑上面查找到文件,潜意识里面认…

SAP ABAP SY-REPID 变化「Note」

6.10 前(知悉) SY-CPROG The name of the calling program in an external routine, otherwise the name of the current program. 外部例程中调用程序的名称,否则为当前程序的名称 SY-REPID Name of the current ABAP program. For externa…

第一章-操作系统引论

🌞欢迎来到操作系统的世界 🌈博客主页:卿云阁 💌欢迎关注🎉点赞👍收藏⭐️留言📝 🌟本文由卿云阁原创! 🙏作者水平很有限,如果发现错误&#xff…

解决数据兼容性问题

数据兼容性问题解决 问题说明 最近经常遇到新老数据兼容性的问题:某些新同事更改代码后,没有兼容旧数据,已有用户的数据显示不全或者错误,很麻烦。 技术层面,就是某个数据或者字段,存储在服务器上&#…

java后端工程师面试题(笔试):2022-11-04 经历(一)

java后端工程师面试题(笔试):2022-11-04: 面试题:总分100 1、关于盒子模型(5分) 1)盒子模型的种类有几种?分别是什么?(1分) 2种,分别是1、W3C标准盒子模型 2、IE盒子模型2) 容器中使用di…

射频已调波同步广播技术在山区高速公路同步广播建设中的应用

北京恒星科通发布于2023-2-2 我国高速公路建设速度的加快,目前我国已经建成通车的高速公路总里程已经达到14万公里,高速公路的安全与信息化建也达到了快速发展,高速公路调频广播覆盖一直是困扰高速公路管理方的一个重要问题,我国…

实时分析全面赋能金融业务,马上消费基于 Apache Doris 构建实时数仓的实践

导读: 近年来,马上消费的业务体量呈飞跃式增长,每天产生数据可达上千亿条,如何更高效挖掘这些数据的价值,成为了其必须要面临的挑战。随着各业务对实时数据分析的需求越来越强烈,马上消费于 2021 年引入 Ap…

点云处理指南介绍

目录 一、点云处理介绍: 二、Open3D文章目录: Open3D几何部分(Geometry) 点云处理(点云IO/可视化/数据结构/下采样/凸包计算/裁减/法向量估计/聚类/隐藏点移除/平面分割/最小外接矩形/外点移除) 面片&…

HTML5+CSS3(三)-全面详解(学习总结---从入门到深化)

目录 Form表单 表单元素 学习效果反馈 表单元素一 文本框 密码框 单选按钮 学习效果反馈 表单元素二 复选框 文件 提交按钮 重置按钮 学习效果反馈 表单元素三 下拉列表 多行文本框 label 学习效果反馈 HTML5新增type类型一 url search tel color 学习效果反馈 HTML5新增…

「Python|网页开发」如何使用Django快速开始进行网页开发:写个Hello World!

本文主要介绍如何从零开始借助django框架快速启动一个网页服务器然后进入编写HTML页面的阶段。 文章目录安装django创建并启动网页项目在网页项目中创建一个应用创建页面并设置好对应关系安装django Django是Python的一个第三方库,里面已经将编写网页需要的代码结构…

如何更改报表控件 Stimulsoft BI 服务器中的地址和端口?

在本文中,我们将主要讨论如何在 Stimulsoft BI Server 中设置基本参数,具体来说,也就是如何更改服务器的地址和端口? 为什么需要更改服务器地址和端口? 在部署报表服务器时,需要指定其地址,实…

使用Websockets和Vert.x进行实时竞价

翻译: 白石(https://github.com/wjw465150/Vert.x-Core-Manual) 原文地址: https://vertx.io/blog/real-time-bidding-with-websockets-and-vert-x/ 在过去的几年中,用户对网络应用程序的期望发生了变化。在拍卖竞价过程中,用户不再需要按下刷新按钮来检…

【C++】STL — map和set的介绍 + 使用

文章目录📖 前言1. 键值对的引入⚡2. 树形结构的关联式容器🌟3. set的介绍 使用⭐4. map的介绍 使用⭐🏁4.4.1 利用map统计次数:🏁4.4.2 std::map::operator[]📖 前言 本章将继续学习STL中的两个很重要的…

23.2.2打卡 2023牛客寒假算法基础集训营5 ABCDHKL 最详细的一集

A 这题据说可以贪心写 我为了省事直接upper二分第一个大于x的商品然后向前遍历完事 /* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆⠹⣿⣿⢾⣟⣯⣿⣿⣿⣿⣿⣿⣽⣻⣿⣿⣿⣿⣿⣿⣿ ⣿⣿⣿⣿⣿⣿⣻⣽⡿⣿⣎⠙⣿⣞⣷⡌⢻⣟⣿⣿⣿⣿⣿⣿⣿…

使用动态创建pinia时报injection “Symbol(pinia)“ not found

前阵发现项目内用pinia报了injection "Symbol(pinia)" not found这个错误,因为前一阵用并没有这个问题。问了相关同事后发现是他新建了节点后调用的,导致的问题。 出现的警告如下图: 这问题排除了比较久,为什么呢&…

python自动化办公--pyautogui控制鼠标和键盘操作

在公司某些工作场景下,需要大量重复的工作,重复的工作完全可以通过python软件的自动化实现,省时省力。本文分享python自动化办公的利器之一--pyautogui,通过pyautogui可以轻松控制鼠标和键盘操作。 PyAutoGUI是一个纯Python的GUI自…

纯滞后系统的大林控制算法

大林控制算法原理早在1968年,美国IBM公司的大林(Dahlin)就提出了一种不同于常规PID控制规律的新型算法,即大林算法。该算法的最大特点是将期望的闭环响应设计成一阶惯性加纯延迟,然后反过来得到能满足这种闭环响应的控…

Linux服务器之间设置共享目录

前言有时候我们需要在两台linux服务器之间共享资源,例如在服务器A上面部署了一个大文件上传程序,但是需要将文件上传到服务器B的某个目录下面,因为上传大文件,需要先将文件所有分块单独上传到服务器B,然后在服务器B上面…

数字文档管理解决财务部门哪些常见问题?

如今,会计部门实施文档管理和自动化工作流程系统至关重要。这些组织要么缺乏数字系统,要么没有充分利用其文档管理解决方案的潜力。 数字文档管理解决财务部门哪些常见问题? 1.错过提前付款折扣:供应商经常为提前付款提供折扣&am…