进程间通信

进程间通信的基本概念。

顺序程序与并发程序特征

顺序程序特征

  • 顺序性
  • 封闭性
  • 确定性
  • 可再现性

并发程序特征

  • 共享性
  • 并发性
  • 随机性

进程互斥

由于各进程要求共享资源,而且这些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥。系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。
在进程中涉及到互斥资源的程序段叫临界区。


进程同步

进程同步指的是多个进程需要互相配合共同完成一项任务。


进程间通信的目的

数据传输:一个进程需要将它的数据发送给另一个进程;
资源共享:多个进程之间共享同样的资源;
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止是要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。


进程间通信发展

  • 管道
  • System V 进程间通信
  • POSIX进程间通信

进程间通信分类

  • 文件
  • 文件锁
  • 管道(pipe)和有名管道(FIFO)
  • 信号(signal)
  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁
  • 套接字(socket)

System V IPC & POSIX IPC

  • System V IPC
    • System V 消息队列
    • System V 共享内存
    • System V 信号量
  • POSIX IPC
    • 消息队列
    • 共享内存
    • 信号量
    • 互斥量
    • 条件变量
    • 读写锁

进程间共享信息的三种方式


IPC对象的持续性

  • 随进程持续:一直存在直到打开的最后一个进程结束。(如pipe和FIFO)
  • 随内核持续:一直存在直到内核自举或显示删除(如System V消息队列、共享内存、信号量)
  • 随文件系统持续:一直存在直到显式删除,即使内核自举还存在。(POSIX消息队列、共享内存、信号量如果是使用映射文件来实现)

死锁

死锁是指多个进程之间相互等待对方的资源,而在得到对方资源之前又不释放自己的资源,这样,造成循环等待的现象。如果所有进程都在等待一个不可能发生的事,这进程则处于死锁。


死锁产生的必要条件

  • 互斥条件:进程对资源进行排他性使用,即在一段时间内某资源仅为一个进程所占用。
  • 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不变。
  • 不可剥夺条件:进程已获得的资源在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
  • 环路等待条件:各个进程组成封闭的环形链,每个进程等待下一个进程所占用的资源。

防止死锁办法

  • 资源一次性分配(破快请求和保持条件)
  • 可剥夺资源(破快不可剥夺条件)
  • 资源有序分配法(破坏循环等待条件)

死锁避免

  • 预防死锁的几种策略,会严重地损害系统性能,因此在避免死锁时,要施加较弱的限制,从而获得较满意的系统性能。
  • 由于在避免死锁的策略中,允许进程动态地申请资源。因此,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。

银行家算法

  • 为保证资金的安全,银行家规定:
    • (1)当一个顾客对资金的最大需求量不超过银行家的现有的资金时就可以接纳该顾客;
    • (2)顾客可以分期贷款,但贷款的总数不能超过最大需求量;
    • (3)当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能时顾客在有限的时间里得到贷款;
    • (4)当顾客得到所需的全部资金后,一定能在有限时间里归还所有的资金。

哲学家进餐问题

  • 五个哲学家在一个圆桌就餐,每个人都必须拿到两根筷子才能用餐
  • 哲学家就餐问题解法:
    • 服务生解法
    • 最多4个哲学家
    • 仅当一个哲学家两边筷子都可用时才允许他拿筷子
    • 给所有的哲学家编号,奇数号的哲学家必须先拿左边的筷子,偶数号的哲学家则反之

信号量

  • 信号量和P、V是由Dijsktra(迪杰斯特拉)提出的
  • 信号量
    • 互斥:P、V在同一个进程中
    • 同步:P、V在不同进程中
  • 信号量值含义
    • S>0:S表示可用资源的个数
    • S=0:表示无可用资源,无等待进程
    • S<0:|S|表示当前等待进程的个数
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      struct semaphore {
      int value;
      pointer_PCB queue;
      };
      P(s) {
      s.value--;
      if (s.value < 0) {
      该进程状态置为等待状态
      将该进程的PCB插入相应的等待队列s.queue末尾
      }
      }
      V(s) {
      s.value++;
      if (s.value<=0) {
      唤醒相应等待进程队列s.queue中等待的一个进程
      改变其状态为就绪态
      并将其插入到就绪状态
      }
      }