进程与线程学习笔记

进程与线程学习笔记

    • 1.进程
      • 1.1 进程模型
      • 1.2 进程的创建
      • 1.3 进程的终止
      • 1.4 进程的层次结构
      • 1.5 进程的状态
      • 1.6进程的实现
      • 2.1.7 多道程序设计模型
    • 2.线程
      • 2.1 线程的使用
      • 2.2 经典的线程模型
      • 2.3 POSIX线程
      • 2.4 在用户空间中实现线程
      • 2.6 在内核中实现线程
    • 3.进程间通信
      • 3.1竞争条件
      • 3.2临界区
      • 3.3忙等待的互斥
        • 1. 屏蔽中断
        • 2. 锁(共享)变量
        • 3.严格轮换法
        • 4.Peterson解法
        • 5.TSL指令
      • 3.4睡眠与唤醒
      • 3.5信号量(semaphore)
      • 3.6互斥量
        • 1.快速用户区互斥量futex
        • 2.pthread中的互斥量
      • 3.7管程
      • 3.8 消息传递
        • 1.消息传递系统的设计要点
      • 3.9屏障
      • 3.10 读-复制-更新

1.进程

1.1 进程模型

在进程模型中,计算机上所有可运行的软件,通常也包括操作系统,被组织成若干顺序进程(sequential process),简称进程。一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。进程是某种类型的一个活动,它有程序、输入、输出以及状态。

1.2 进程的创建

4种主要的事件会导致进程的创建

  1. 系统初始化
  2. 正在运行的程序执行了创建进程的系统调用
  3. 用户请求创建一下新进程
  4. 一个批处理作业的初始化

1.3 进程的终止

进程终止的条件

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

1.4 进程的层次结构

某些系统中,当进程创建了另一个进程后,父进程和子进程就以某种形式继续保持关联。

1.5 进程的状态

进程与线程学习笔记_第1张图片

1.6进程的实现

为了实现进程模型,操作系统维护一张表格(一个结构数组),即进程表(process table)。每个进程占用一个表项。
进程与线程学习笔记_第2张图片

单个CPU上是如何维持多个顺序进程的。
进程与线程学习笔记_第3张图片

2.1.7 多道程序设计模型

多道程序设计可提高CPU的利用率。
进程与线程学习笔记_第4张图片

2.线程

2.1 线程的使用

为什么需要线程?

  1. 许多应用中同时发生着多种活动。通过将这些应用程序分解成可以准并运行的多个顺序线程,程序设计模型会变得简单。有了这样的抽象,就不必在考虑中断、定时器和上下文切换。
  2. 线程比进程更轻量级,所以它们比进程更容易创建,也更容易撤销。
  3. 如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠进行,从而会加快应用程序执行的速度。
    进程与线程学习笔记_第5张图片

2.2 经典的线程模型

进程模型基于两种独立的概念:资源分组处理与执行。
进程与线程学习笔记_第6张图片
线程之间是没有保护的,原因是:

  1. 不可能
  2. 也没有必要
    进程与线程学习笔记_第7张图片
    进程与线程学习笔记_第8张图片
    通常每个线程会调用不同的过程,从而有一个各自不同的执行历史,这就是为什么每个线程需要有自己的堆栈的原因。
    复制进程时,复制的线程怎么办?共享文件,分配内存时引发的问题。

2.3 POSIX线程

可移植的线程程序
进程与线程学习笔记_第9张图片

2.4 在用户空间中实现线程

优点

  1. 用户级线程包可以在不支持线程的系统上实现。
  2. 线程切换至少比陷入内核要快上一个数量级。
  3. 不需要陷入内核,不需要上下文切换,也不需要对内存高速缓存进行刷新。
  4. 允许每个进程有自己定制的调度算法。
    只要堆栈指针和程序计数器一被切换,新的线程就就又自动投入运行。

缺点

  1. 如何实现阻塞系统调用。
  2. 缺页中断引起的进程阻塞,导致其他线程也不能运行。
  3. 一个线程开始运行,那么在该进程中的其他线程就不能运行。

进程与线程学习笔记_第10张图片
进程表
每个进程需要有其专用的线程表(thread table)

2.6 在内核中实现线程

缺点

  1. 所有能够阻塞线程的调用都以系统调用的形式实现,这与运行时系统(用户空间)相比,代价是相当可观的。

3.进程间通信

进程间通信的是三个问题

  1. 一个进程如何把信息传递给另一个
  2. 确保两个或更多的进程在关键活动中不会出现交叉
  3. 正确的顺序

3.1竞争条件

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

3.2临界区

我们把对共享内存进行访问的程序片段称作临界区
进程与线程学习笔记_第11张图片

避免竞争条件解决方案的4个条件

  1. 任何两个程序不能同时处于
  2. 不应对CPU的速度和数量做任何的假设
  3. 临界区外运行的进程不得阻塞其他进程
  4. 不得使进程无限期等待进入临界区

3.3忙等待的互斥

1. 屏蔽中断

屏蔽中断仅对执行disable指令的那个CPU有效,其他CPU仍将继续运行,并可以访问内存

2. 锁(共享)变量

非原子性操作,与假脱机目录一样的疏漏 。假设一个进程读出锁变量的值并发现它为0,而恰好在它将值设置为1之前,另一个进程被调度运行,将该变量设置为1。当第一个进程再次运行是,它同样也将该值设置为1,则此时同时有两个进程进入临界区中。

3.严格轮换法

进程与线程学习笔记_第12张图片
严格轮换法主要是因为对同一变量比较了不同的值,防止了比较相同值时,在相同时间点的漏洞

连续测试一个变量直到某个值出现为止,称为忙等待
用于忙等待的锁称为自旋锁
临界区外的进程可阻塞其他进程。

4.Peterson解法

perterson解法与严格轮换法的区别在于多了一个数组来记录进程的状态,比较的是对方的状态,所以不会像严格轮换法导致进程外的进程阻塞其他进程。
进程与线程学习笔记_第13张图片

5.TSL指令

硬件支持的一种方案
TSL RX,LOCK 测试并加锁,它将一个内存字lock读到寄存器RX中,然后在该内存地址上存一个非零值。
锁住存储总线不同于屏蔽中断。
进程与线程学习笔记_第14张图片
每个进程有自己的一组寄存器,若线程是在内核中实现的,那么每个线程也有自己的一组寄存器。在TSL测试时锁的值时存在自己的寄存器里面,所以不会有竞争条件发生
忙等待缺点:

  1. 浪费了CPU时间
  2. 可能产生优先级反转问题 。当H的优先级较高,L的优先级较低,L在临界区运行,H到了就绪状态就会忙等待,L不会被调度,所以H将一直忙等待下去。

3.4睡眠与唤醒

sleep wakeup

if(count ==0) sleep();不是一个原子操作。所以存在,wakeUp 信号丢失问题
唤醒等待位: 当一个wakeup信号发送给一个清醒的进程信号时,将该位置1.随后,当该进程要睡眠时,如果唤醒等待位为1,则将该位清除,而该进程仍然保存清醒。
wakeup唤醒特定的进程。

3.5信号量(semaphore)

一个信号量可以为0(表示没有保存下来的唤醒操作)或者值为正值(表示有一个或多个唤醒操作)。
共两个或多个进程使用的信号量,其初值为1,保证同时只有一个进程可以进入临界区,称作二元信号量
down操作:检查值是否大于0,大于0,将其值减1,并继续;若值为0,则进程将睡眠,此时down操作并未结束。
up操作:对信号量的值增加1。

信号量mutex用于互斥,保存任一时刻只有一个进程读写缓冲区和相关变量。
empty 和 full 用来记录,个信号的数量,避免了,信号的丢失。信号量full和empty用来保证某种事件的顺序发生或不发生。

3.6互斥量

如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量
没有计数能力,解锁和加锁两种状态。
0表示解锁,信号量当是0的时候阻塞。
mutex_lock mutex_unlock
如果有可用的TSL 和 XCHG指令,就可以很容易的在用户空间中实现。
进程与线程学习笔记_第15张图片

公共缓冲区的两种方案
1.共享数据结构,放在内核中,并且只能通过系统调用来访问。
2.让进程和其他进程共享部分地址空间。

1.快速用户区互斥量futex

实现了基本的锁(很像互斥锁),但避免了陷入内核,除非它真的不得不这样做。
futex包含两个部分:一个内核服务和一个用户库。
是Linux对轻量级锁和重量级锁的自动转换功能。

2.pthread中的互斥量

互斥量

pthread_mutex_

3.7管程

一种高级同步原语。一个管程是一个由过程、变量及数据结构等组成的一个集合,它们组成一个特殊的模块或软件包。
管程有一个很重要的特性,即任一时刻管程中只能有一个活跃进程,这一特性使管程能有效地完成互斥。

3.8 消息传递

消息传递(message passing)。这种进程间通信的方法使用两条原语send和receive,它们像信号量而不像管程,是系统调用而不是语言成分。
进程与线程学习笔记_第16张图片

1.消息传递系统的设计要点

**消息确认:为了防止消息丢失,发送方和接受方可以达成如下一致:一旦接收到信息,接收方马上回送一条特殊的确认(acknowledge)**消息。发送方在一段时间间隔内未收到确认,则重发消息。
收到两次相同消息,用连续的序号来解决此问题。
身份认证(authentication) 问题
在同一台机器上将消息从一个进程复制到另一个进程通常比信号量操作和进入管程要慢。

3.9屏障

屏障是准备用于进程组而不是用于双进程的生产者-消费者这类情形的。
在有些应用中划分了若干阶段,并且规定,除非所有的进程都就绪准备着手下一个阶段,否则任何进程都不能进入下一个阶段。

3.10 读-复制-更新


读-复制-更新(Read-Copy-Update,RCU),将更新过程中的移除和再分配过程分离开来。

你可能感兴趣的:(进程,操作系统)