进程和线程

  操作系统相关的内容可以分为内存管理、进程和线程、死锁三个部分。本篇文章记录进程和线程部分。

  • 内存管理
  • 死锁

1. 进程

  操作系统最核心的概念就是进程:它是对正在运行程序的一个抽象,从操作系统角度来看,进程 = 程序 + 数据 + PCB 。换句话说,进程可以看作某一时刻的程序状态。

1.1. 进程模型

  在进程模型中,计算机上所有可运行的软件,包括操作系统,被组织成若干顺序进程,简称进程。一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。

  内存中多道程序分别有自己的逻辑程序计数器,当程序运行时,它的逻辑程序计数器被装入物理程序计数器中;当程序运行结束时,物理程序计数器被保存到内存中该进程的逻辑程序计数器中。从进程的角度来看,每个进程拥有自己的CPU和程序计数器,但实际上只有一个物理CPU在按照调度算法切换,而且只有一个物理程序计数器指示当前CPU上运行程序所运行到的指令位置。

  进程和程序的区别很微妙。如果一个程序运行两遍,则对应2个进程,操作系统会使两个进程共享代码,因此只有一个副本放到内存中。

1.2. 进程创建和终止

  UNIX系统中只有一个系统调用来创建新进程:fork。调用fork后,两个进程拥有相同的内存映像,同样的环境字符串和同样的打开文件。父进程和子进程拥有不同的地址空间,如果某个进程在其地址空间修改了一个字,这个修改对其他进程而言是不可见的,另外不可写的内存空间是共享的。某些UNIX的实现,子进程共享父进程的所有内存,但这种情况下内存通过写时复制共享,这意味着一旦两者之一想要修改部分内存,则这块内存首先被明确地复制,以确保修改发生在私有内存区域。再次强调,可写内存是不可以共享的。

以下四种情况会导致进程的创建:

  1. 系统初始化(守护进程)。
  2. 用户请求创建一个新进程(交互式系统中用户双击图标)。
  3. 正在运行的程序执行了创建进程的系统调用(Redis持久化工作)。
  4. 一个批处理作业的初始化(用户远程提交一个作业,操作系统创建一个进程,运行其输入队列中的下一个作业)。

以下四种情况会导致进程的终止:

  1. 正常退出(自愿)。
  2. 出错退出(自愿)。
  3. 严重错误(非自愿)。
  4. 被其他进程杀死(非自愿)。

1.3. 进程的状态

1.4. 进程的实现

  为实现进程模型,操作系统维护着一张表格,即进程表(结构体数组,或链表)。每个进程会占用一个进程表项(PCB),PCB中包含程序计数器、堆栈指针、内存分配情况、所打开文件的状态、账号和调度信息,以及进程由运行态到就绪态或阻塞态时必须保存的信息,从而保证该进程随后再次启动,像从未被中断过一样。

  所有的中断都从保存寄存器开始,与每一I/O类关联的是一个称作中断向量的的位置,它是靠近内存底部的固定区域,包含中断服务程序的入口地址。

中断导致进程切换的过程如下:

  1. 当一个磁盘中断发生时,中断硬件将程序计数器、程序状态字和其他寄存器压入堆栈,计算机随即调到中断向量所指示的位置。以上由硬件完成,接下来会由软件(中断服务程序)来接管剩余工作(把寄存器中数据保存到PCB中)。

  2. 对当前进程A而言,中断服务程序会把压入堆栈中的寄存器数据保存到PCB中,随后会从对战中删除由中断硬件机制存入堆栈的那部分信息,并将堆栈指针指向一个由进程处理程序所使用的临时堆栈。其中将堆栈信息保存到PCB中的操作一般使用汇编完成,这段汇编程序可供所有中断使用,因为无论什么类型的中断,有关保存寄存器的工作则是一样的。

  3. 汇编程序将堆栈中硬件信息保存到PCB后,调用一个C过程处理某个特定的终端类型剩下的工作,之后会使A进程进入就绪态,接着调用调度程序,决定随后该运行哪个进程。

  4. 最后将控制转给一段汇编代码,为当前进程PCB信息装入寄存器值以及内存映射,并运行该进程。

2. 线程

  传统操作系统中,每个进程有一个地址空间和一个控制线程,事实上,这几乎就是进程的定义。在引入多线程概念后,并行实体拥有共享同一个地址空间和所有可用数据的能力,对于某些应用而言,这些能力是必需的,而这正是多进程模型(它们拥有不同的地址空间)所无法表达的。

  若多个线程都是CPU密集型的,并不能获得性能上的增强,但如果存在大量计算和I/O处理,多线程会允许这些活动彼此重叠进行,会加快应用程序执行速度。进程存放程序正文、数据、其它资源的地址空间,这些资源包括,打开的文件、子进程、即将发生的定时器、信号处理程序、账号信息等。

2.1. 经典的线程模型

  进程模型基于两种独立概念:资源分组与执行。有时这两种概念分开会更好,这就引入了“线程”概念。理解进程的一个角度是,用某种方法把相关的资源集中在一起。

  进程拥有一个可执行的线程。线程中拥有一个程序计数器(记录接下来要执行哪一条指令),寄存器(保存线程当前的工作变量),堆栈(记录执行历史,其中每一帧保存了一个已调用,但还没有从中返回的过程)。

  线程概念试图实现的是,共享一组资源的多个线程可以为完成某一任务而共同工作。

2.2. 用户空间中实现线程

  把整个线程包存放在用户空间中,内核对线程包一无所知。从内核角度考虑,就是按正常的方式管理,即单线程进程。线程在一个运行时系统的上层运行,该运行时系统是一个管理线程的过程集合。常用的几个过程有,pthread_createpthread_exitpthread_joinpthread_yield

  在用户空间管理线程时,每个进程需要有其专用的线程表,用来跟踪该进程中的线程,记录每个线程的程序计数器,堆栈指针,寄存器和状态等,线程表由运行时系统管理。

  用户级线程线程切换效率更高。当某个线程做了一些会引起本地阻塞的事件之后,调用一个运行时系统中的过程,检查线程是否要进入阻塞态,如果是,把该线程的寄存器保存到线程表中,根据线程表查看是否有可运行的就绪线程,并把新线程的保存值重新装入寄存器,只要堆栈指针和程序计数器被切换,就算完成了线程切换,新的线程又自动投入运行。类似的线程切换至少比陷入内核快一个数量级。

  用户级线程线程调度效率更高。在线程完成运行时,例如调用thread_yield,会把线程的信息保存到线程表,进而调用线程调度程序来选择另一个要运行的程序,保存线程状态的过程和调度程序都只是本地过程,所以启动它们比内核调用效率更高。另外不需要陷入内核,不需要上下文切换,也不需要对内核告诉缓存进行刷新,这使得线程调度非常快捷。

  用户级线程的一个问题是,如何实现阻塞系统调用。使用线程的一个主要目标是,首先允许每个线程使用阻塞调用,但还要避免被阻塞的线程影响其他线程。一种解决方案是,如果某个调用会阻塞,就提前通知。某些UNIX系统中,select系统调用允许调用者通知预期的read是否阻塞。首先调用select,只有安全情形(不阻塞)才进行read调用。如果read调用会发生阻塞,不进行该调用,而是运行另一个线程。

  用户级线程另一个问题是,如果线程开始运行,那么该进程中其它线程就不能运行,除非第一个线程自动放弃CPU。在一个单独的进程内部,没有时钟中断,不可能用轮转调度方式调度线程。除非某个线程能按照自己的意志进入运行时系统,否则调度程序没有任何机会,称为线程永久运行问题。

  对用户级线程最大的争议是,程序员通常在经常发生线程阻塞的应用中才希望使用多线程。例如多线程Web服务器,这些线程会持续进行系统调用,如果原有线程已经阻塞,很难让内核进行线程切换,如果让内核消除这些情形,就要持续进行select系统调用,以便检查read系统调用是否安全。

  对于那些CPU密集型且极少有阻塞的应用程序而言,使用多线程目的又何在呢?所以没有人会提出真正用多线程来计算前n个素数或者下象棋等工作。

2.3. 在内核实现线程

  在内核中记录系统中所有线程的线程表。当某个线程希望创建一个新线程或者撤销一个新线程时,它进行一个系统调用,该系统调用通过对线程表的更新完成线程创建和撤销的工作。

  所有能够阻塞线程的调用都以系统调用的形式实现,当一个线程阻塞时,内核根据其选择,可以运行同一进程中的另一线程或另一进程中的线程,而用户级线程中,运行时系统始终运行自己进程中的线程,直到内核剥夺它的CPU为止。

  内核线程不需要任何新的、非阻塞系统调用。

3. 进程间通信

  进程通信(Inter-Process Communication,IPC)要解决三个问题:1. 一个进程如何把消息传递给另一个进程 。2. 保证两个甚至更多个进程在关键活动中不会出现交叉。3. 进程按正确顺序执行。

  第一个问题在线程中容易实现(它们共享同一个地址空间)。另外两个问题同样适用于线程,同样的问题可用同样的方法解决。

3.1. 竞争条件

  在一些操作系统中,协作的进程可能共享一些彼此都能读写的公用存储区,这个公用存储区可能在内存中(内核中数据结构),也可能是一个共享文件。

  两个或多个进程读某个共享数据,而最后结果取决于进程运行的精确顺序,称为竞争条件。

3.2. 临界区

  操作系统的一个主要设计内容是,为实现互斥而选择适当的原语。我们把对共享内存进行访问的程序片段称作临界区。如果我们能够使两个进程不同时处于临界区,就能避免竞争条件。

参考文献

[1] (荷) Andrew S.Tanenbaum,(荷)Herbert Bos著. 现代操作系统. 陈向群等译. 北京:机械工业出版社,2017
[2] https://www.cnblogs.com/CareySon/archive/2012/04/25/2470063.html

现代操作系统学习笔记二、进程和线程相关推荐

  1. 操作系统学习笔记-2.1.5线程概念和多线程模型

    操作系统学习笔记-2019 王道考研 操作系统-2.1.5线程概念和多线程模型 文章目录 5线程概念和多线程模型 5.1知识概览 5.2 什么是线程?为什么要引入线程? 5.3引入线程及之后,有什么变 ...

  2. 哈工大操作系统学习笔记五——内核级线程实现

    哈工大os学习笔记五(内核级线程实现) 文章目录 哈工大os学习笔记五(内核级线程实现) 一. 中断入口.中断出口(前后两段) 1. 从int中断进入内核(中断入口第一段) 2.中断出口(最后一段) ...

  3. linux 驱动线程与进程,Linux内核学习之二-进程与线程

    一.操作系统的功能 根据维基百科的解释,一个操作系统大概包括以下几个功能: 进程管理(Processing management) 安全机制(Security) 内存管理(Memory managem ...

  4. Python学习笔记:进程和线程(承)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  5. Python学习笔记:进程和线程(起)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  6. Java学习笔记:进程与线程、BIO、NIO、Selector

      文章目录 一.进程和线程 1.进程(Process) (1)概念 (2)从三个维度看进程模型

  7. 操作系统学习笔记_03_进程的概念与操作

    1.进程的概念和状态 进程的概念常常和程序糅合在一起,但两者实际是不一样的.首先,"进程"所包含的内容比"程序"丰富."程序"这个概念可以用 ...

  8. 操作系统学习笔记7——进程管理中的数据结构:进程控制块

    进程控制块(PCB)--最重要的记录型数据结构 PCB的作用 1.作为独立运行的基本单位的标志: 系统创建一个新进程时,就为它建立一个PCB,进程结束时回收PCB,进程也随之消亡,系统通过感应PCB来 ...

  9. 计算机操作系统学习笔记_6_进程管理 --死锁

    一.死锁的概念 1.死锁的概念 系统中两个或两个以上的进程无限期地相互等待永远不会发生的条件,系统处于一种停滞状态,这种情况称为死锁. 2.死锁产生的原因 (1)进程推进顺序不当 (2)对互斥资源的分 ...

最新文章

  1. java(十)IO流
  2. 反射 -- 业务需求:执行某个类中全部的以test为开头的无参数无返回值的非静态方法。...
  3. 基于XFS的NAS数据恢复可以做了
  4. 自从Python数据可视化出了这个模块后,数据可视化就再简单不过了
  5. 5.4 Spring AOP
  6. mysql分布式一致性hash_分布式哈希一致性
  7. Jetson Nano安装pytorch 基于torch1.6和torchvision0.7
  8. 799元!乐视智能门锁新品Le1S发布
  9. ArcGIs创建企业级数据库
  10. masm编译.asm文件报错fatal errorA1000: cannot open file
  11. QCC3007-button篇 使用ADK Configuration Tool配置按键
  12. ZPL指令打印标签时出现白色窄条的坑
  13. Android 广告视频循环播放 缓存 处理方案
  14. 显示器间歇性黑屏问题排查
  15. 网易云音乐黑胶会员免费领取
  16. RocketMQ(17)——Broker可配置参数
  17. python随机生成生日测试生日悖论
  18. 建议118:使用SecureString保存密钥等机密字符串
  19. unity可以用中文了?代码也可以中文?
  20. 100首经典英文歌曲

热门文章

  1. DirectSound 笔记
  2. 【SQLITE3】SQLITE3菜鸟笔记
  3. 追逐自己的梦想----------辅助制作第一课:人物属性分析
  4. QGIS管网水力模型inp文件制图初探
  5. BeginPaint和GetDC
  6. 多线程内使用GetDC的注意问题
  7. atheros无线网卡 linux,解决Ubuntu 11.04下Atheros无线网卡不能上网的问题
  8. 证券期货业数据安全管理 与保护指引 附下载地址
  9. 中国汽车流通协会 :2018年第39期车市扫描
  10. Eclipse下执行Python文件出现SyntaxError: Non-UTF-8 code starting with '\xb4' in file