[读书笔记]并发性:互斥和同步

来源:互联网 发布:python sum(axis=1) 编辑:程序博客网 时间:2024/06/05 15:51

互斥和同步

并发相关的术语解释

  • 原子操作。一个函数或动作由一个活多个指令序列实现,对外是不可见的,指令序列的作为一个组来执行,要么都不执行。
  • 临界区资源。多个进程活线程所需的共享资源
  • 临界区。使用临界区资源的那一部分程序,它是一段代码,这段代码中进程将访问共享资源,当另一个
    进程已经在这段代码中运行时,这个进程就不能在这段代码中执行。
  • 死锁。两个活两个以上的进程因其每个进程都在等待其他进程做完某些事情而不能继续执行。
  • 互斥。当一个进程在临界区访问共享资源时,其他进程不能进入该临界区访问任何共享资源
  • 竞争条件。多个线程或者进程在读写一个共享数据时,结果依赖于它们执行的相对时间
  • 饥饿。一个可运行的进程尽管能继续执行但被调度程序无限期地忽视,而不能被调度执行的情形
  • 忙等待。当一个进程位于其临界区内,试图进入该进程临界区的另外在进入代码处(判断条件)连续循环

并发出现的环境

  • 多应用程序。多道程序设计技术允许在多个活动的应用程序间动态共享处理器时间
  • 结构化应用程序。作为模块化设计和结构化程序设计的扩展,一些应用程序可以被有效地设计成一组并发进程
  • 操作系统结构。操作系统自身常常作为一组进程或线程实现

并发的原理

进程相对执行速度不可预测,它取决于其他进程的活动、操作系统处理中断的方式及操作系统的调度策略。这种执行速度的不可预测带来了如下的危险:

  • 全局资源共享充满了危险。这些资源包括:处理器时间、存储器、文件、I/O设备
  • 操作系统很难对资源进行最优化配置
  • 定位程序设计时非常困难的

因此,我们需要控制对共享资源的访问(互斥)

进程的交互

进程交互时,必须满足两个基本要求:同步和通信。为了实施互斥,进程间需要同步,为了合作,进程间需要交换信息。

进程交互分三种情况:

  1. 进程之间互相不知道对方的存在
  2. 进程间接知道对方的存在
  3. 进程直接指导对方的存在

进程间的资源竞争,当并发进程使用同一个资源时,它们之间会发生冲突。竞争进程面临三个控制问题:

  • 互斥
  • 死锁
  • 饥饿

互斥的要求

为了提供对互斥的支持,必须满足以下要求:

  • 在与相同资源或共享对象临界区有关的所有进程中一次只允许一个进程进入临界区
  • 一个非临界区停止进程不能干涉其他进程
  • 不允许出现需要访问的临界区的进程被无限延迟
  • 当没有进程在临界区时,任何需要进入临界区的进程能够立即进入
  • 对相关进程的执行速度和处理器数目没有任何要求和限制
  • 一个进程驻留在临界区中的时间必须是有限的

互斥的实现

中断禁用

专用机器指令

在硬件级别上,对存储单元的访问排斥对相同单元的其他访问

信号量

信号量相关术语解释

  • 计数信号量。用于进程间传递信号的一个整数值,在信号量上只有三种原子操作:初始化,递减,增加。递减操作涌来阻塞一个进程,增加操作用来解除阻塞一个进程。
  • 二元信号量。只取0值和1值的信号量
  • 互斥量。它是一种二元信号量,区别在于为其加锁的进程和其解锁的进程必须为同一个进程
  • 条件变量。用来阻塞进程或线程,知道特定条件为真
  • 管程。一种编程语言结构,在一个抽象数据类型中封装了变量、访问过程和初始化代码。管程的变量只能由管程自己的访问过程来访问,每次只能有一个进程在其中执行,访问过程即临界区,管程可以有一个等待进程队列

管程

管程是由一个或多个过程、一个初始化序列和局部数据组成的软件模块,其主要特点如下:

  • 局部数据变量只能被管程的过程访问,任何外部过程不能访问
  • 一个进程通过调用管程的一个过程进入管理
  • 在任何时候,只能有一个进程在管程中执行,调用管程的任何其他进程都被阻塞,以等待管程可用

前两个特点,我们会想到面相对象的软件设计。在java中,通过新建对象,私有成员变量,成员方法,实现管程功能。在该对象里,必须包含同步工具(java里,调用wait和notify方法),确定同步的条件变量,通过条件变量来提供对同步的支持,这些条件变量包含在管程中,并且只有管程对象里才能被访问。

此外,当一个进程难以准确地判定将激活哪个进程时,使用广播。这个很像Android的开源库EventBus。

消息传递

一个进程以消息的形式给另一个指定的目标进程发送信息,执行send原语操作,进程通过执行receive原语接受信息,receive原语中指明发送消息的源进程和消息。

消息的格式

  • 消息头。包含消息的源和目标的标识符,长度域以及判定各种消息类型的类型域和一些额外的控制信息(入创建消息链表的指针域,记录源和目标之间传递的消息的数目、顺序和序号,优先域)
  • 消息体。消息的内容

直接寻址

send原语包含目标进程的标识符。

间接寻址

消息不是直接从发送者发送到接受者,而是发送到一个共享的数据结构上,该结构由临时保存消息的队列组成,该队列称为信箱。

间接寻址通过解除发送者何接收者之间的耦合关系,在消息的使用上允许更大的灵活性。发送者和接收者之间的关系可以是一对一,多对一,一对多核多对多。

进程和信箱的关联可以是静态的,也可以是动态的。端口常常是静态地关联到一个特定的进程上的,也就是说,端口被永久地创建并制定到该进程。在一对一关系中就是典型的静态和永久性的关系。当有很多发送者时,发送者和信箱间的关联可以是动态的,基于这个目的可以使用诸如connect和disconnect之类的原语。

假设使用阻塞receive原语和无阻塞send原语,一组并发进程共享信箱box,它可供所有进程发送和接收消息时使用,该信箱被初始化程一个无内容的消息。希望进入临界区的进程受限试图接收一个消息,如果信箱为空,则该进程被阻塞;一旦进程获得消息,它执行它的临界区。

这种设计在Android上的体现是Handler消息机制。

两个经典的同步问题

生产者/消费者问题

有一个或多个生产者生产某种类型的数据,并放置在有限缓冲区中,有一个消费者从该缓冲区每次取一个项,任何时候,只有一个生产者或消费者访问缓冲区,当缓冲区满时,生产者不会继续向其中添加数据,当缓冲区为空时,消费者不会从中移走数据。

读者/写者问题

有一个由多个进程共享的数据区(文件或内存空间),一些进程只读取这个数据区中的数据,一些进程只往数据区中些数据。要求:任意多的读进程可以同时读;一次只有一个写进程可以写;如果一个写进程正在写操作,那么禁止任何读进程读操作。

并发相关的四种设计问题

  • 进程间的交互
  • 共享资源之间的竞争
  • 多个进程的同步问题
  • 对进程的处理器时间分配问题
1 0
原创粉丝点击