操作系统学习笔记——第四章 互斥、同步与通讯

本文详细介绍了操作系统中并发进程的概念,包括前驱图、并发程序的特性、并发执行的条件。重点讲解了进程互斥,如共享变量、临界区域、互斥的软件和硬件实现,以及各种互斥算法。此外,还深入探讨了进程同步,包括定义、同步机制、信号量与PV操作、经典同步问题的解决方案,如读者/写者问题、生产者/消费者问题等。最后,提到了进程高级通信的两种模式:共享内存和消息传递。
摘要由CSDN通过智能技术生成

文章目录

并发进程

前驱图

  • 有向无环图,图中每个结点表示一个语句、一个计算步骤、或一个进程。
  • 结点间的有向边表示偏序或前趋(precedence relation)关系“→” 。
  • →={( P i P_i Pi P j P_j Pj)| P j P_j Pj启动之前 P i P_i Pi必须已经完成}。
  • P i P_i Pi P j P_j Pj)∈→可记作 P i P_i Pi P j P_j Pj, 称 P i P_i Pi P j P_j Pj的前趋, P j P_j Pj P i P_i Pi的后继。
  • 在前趋图中,没有前趋的结点称为初始结点,没有后继的结点称为终止结点。
  • 每个结点可以有一个权重(weight),它可以表示该结点所包含的程序量或计算时间。

程序的顺序执行

  • 内部顺序性:对于一个进程来说,它的所有指令是按序执行的。
  • 外部顺序性:对于多个进程来说,所有进程的活动是依次执行的。

顺序程序特性

(1)连续性: 指令逐条执行
(2)封闭性: 不受其它程序及外界因素影响
(3)可再现性: 结果与推进速度无关

并发程序特性

(1)间断性:程序交叉执行。
(2)非封闭性:一个进程的运行环境可能被其它进程所改变,从而相互影响。
(3)不可再现性:由于交叉的随机性,并发程序的多次执行可能对应不同的交叉,因而不能期望重新运行的程序能够再现上次运行的结果。

程序并发执行的条件

在失去封闭性的条件下,保持可再现性

读集与写集

  • R ( p i ) = a 1 , a 2 , … , a m R(p_i)={a_1,a_2,…,a_m} R(pi)=a1,a2,,am表示程序 p i p_i pi在执行期间所需读取的所有变量的集合,称为“读集”;
  • W ( p i ) = b 1 , b 2 , … , b n W(p_i)={b_1,b_2,…,b_n} W(pi)=b1,b2,,bn表示程序 p i p_i pi在执行期间所需改变的所有变量的集合,称为“写集”。

Bernstein条件

若两个程序p1,p2满足如下条件,则能够保持可再现性,因而可以并发执行,该条件称为Bernstein条件。
R ( p 1 ) ∩ W ( p 2 ) ∪ R ( p 2 ) ∩ W ( p 1 ) ∪ W ( p 1 ) ∩ W ( p 2 ) = Φ R(p_1)∩W(p_2)∪R(p_2)∩W(p_1)∪W(p_1)∩W(p_2)=Φ R(p1)W(p2)R(p2)W(p1)W(p1)W(p2)=Φ

与时间有关的错误

举例:

  1. 就绪队列的整队问题
  2. 死锁
  • 错误原因之1:
    进程执行不正确的交叉(interleave);

  • 错误原因之2:
    同时对一个公共变量(x)操作,其中一个进程的操作没有结束,另一个进程也对公共变量进行操作,使得公共变量处于一种不确定的状态,用数据库的术语说就是失去了变量x的数据完整性。

  • Remarks:
    上述错误并不是一定发生,而是与进程的推进速度有关,速度是时间的函数,因为这类错误称为与时间相关的错误
    某些交叉结果不正确;必须去掉导致不正确结果的交叉。

进程互斥

共享变量

多个进程都需要访问的变量。

临界区域

访问共享变量的程序段。把临界区与其所对应的共享变量联系起来称为关于某一种共享变量的临界区

共享变量和临界区域的表示

共享变量: shared <一组变量>
临界区域: region <一组变量> do <语句>

进程互斥的定义

多个进程不能同时进入关于同一组共享变量的临界区域,否则可能发生与时间有关的错误,这种现象称为进程互斥。

二层含义:
(1)任何时刻最多只能有一个进程处于同一组共享变量的相同的临界区域;
(2)任何时刻最多只能有一个进程处于同一组共享变量的不同的临界区域。

实现互斥的要求

  • 互斥进入: 一次只允许一个进程进入关于同一组公共变量的临界区;
  • 空闲让进: 临界区空闲时,放行一个进入者;
  • 有限等待: 一个想要进入临界区的进程在等待有限个进程进入并离开临界区后获得进入临界区的机会

调度原则

  • 当关于某一组共享变量的所有临界区均为空闲时,一个要求进入该组共享变量某一临界区的进程应该能够立即进入;
  • 当关于某一组共享变量的某一临界区被占用时,一个要求进入该组共享变量某一临界区的进程应当等待;
  • 当一个进程离开关于某一组共享变量的某一临界区时,应当容许某一个等待进入该组共享变量某一临界区的进程进入;

软件实现

  • 完全用程序实现,不需特殊硬件指令支持。
  • 可用于单CPU和多CPU环境中。
  • 有忙式等待问题

petersom算法

flag表示是否想进入临界区,turn表示轮到谁了
两个进程互斥算法

boolean flag[2];
int turn;
P0:
Do{
   
        flag[0]=true; turn=1;
        while (flag[1] && turn==1);
        临界区
        flag[0]=false;
        其余代码
}while(1);

P1:
Do{
   
        flag[1]=true; turn=0;
        while (flag[0] && turn==0);
        临界区
        flag[1]=false;
        其余代码
}while(1);

Dekkel算法

flag表示是否想进入临界区,turn表示轮到谁了
两个进程互斥算法

int flag[2]; (init 0)
int turn; (0 or 1)

P0:
do{
   
        flag[0]=1;
        while(flag[1])
            if(turn==1){
   
                 flag[0]=0;
                 while (turn==1)
                     skip;
                 flag[0]=1;
            }
        临界区
        turn=1;
        flag[0]=0;
        其余代码
}while(1);

P0:
do{
   
        flag[1]=1;
        while(flag[0])
            if(turn==0){
   
                 flag[1]=0;
                 while (turn==0)
                     skip;
                 flag[1]=1;
            }
        临界区
        turn=0;
        flag[1]=0;
        其余代码
}while(1);

Lamport面包店算法

设置一个发号者,按0,1,2,…, 发号。想进入临界区的进程抓号,抓到号之后按由小到大的次序依次进入。

  • Problem: 两个进程可能抓到相同的号。
    Why? 为保证抓到不同的号,需要互斥机制。
  • Resolution: 若抓到相同的号,按进程编号依次进入。
  • Definition: (a,b)<(c,d) iff (a<c)or(a==c and b<d)

n个进程互斥算法
choosing为true表示正在抓好,否则表示未抓号或已经抓完。
number表示抓到的号

Boolean choosing[0,,n-1];false)
Int number[0,,n-1]; (0)
Pi 进入:
1. choosing[i]=true;
2. number[i]=max{
   number[0],,number[n-1]}+1;
3. choosing[i]=false;
4. For(j=0;j<n;j++){
   
5.     While (choosing[j]) skip;
6.     While (number[j]!=0)and
7.             (number[j],j)<(number[i],i) skip;
8. }

Eisenberg/Mcguire算法

n个进程互斥

enum flag[0,,n-1] (idle, want_in, in_cs);  
int turn;  //0..n-1; 初始任意
flag[i]==idle:  //进程Pi不想进入临界区
flag[i]==want_in:   //进程Pi想进入临界区
flag[i]==in_cs:   //进程Pi想进入或已进入临界区

Pi进入:
Do{
   
      flag[i]=want_in;
      j=turn;
      While (j!=i)
          If (flag[j] != idle) j=turn
          Else  j=(j+1)% n;
      flag[i]=in_cs;
      j=0; 
      While (j<n)and(j==i or flag[j]!=in_cs) do 
          j++;
}while (j!=n);
turn=i;
临界区
Pi离开:
j=(turn+1)% n;
While (flag[j]==idle)
      j=(j+1)% n;
turn=j;
flag[i]=idle;

图书馆登记和注销 要求:有一阅览室,读者进入时必须先在一张登记表上登记。该表中每个表项代表阅览室中的一个座位。读者离开时要消掉其登记信息。阅览室共有50 个座位。登记表每次仅允许一位读者进行登记或注销。 本实验由两个进程组成,分别是登陆和注销进程 使用到的函数和信号量 HANDLE mutex; HANDLE empty; HANDLE full; 创建信号量 HANDLE CreateSemaphore( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,// lpSemaphoreAttributes是信号量的安全属性 可为NULL __in LONG lInitialCount,// lInitialCount是初始化的信号量 __in LONG lMaximumCount,// lMaximumCount是允许信号量增加到最大值 __in_opt LPCWSTR lpName//lpName是信号量的名称 可为NULL ); 创建互斥信号量 HANDLE CreateMutex(  LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针 可为NULL  BOOL bInitialOwner, // 初始化互斥对象的所有者  LPCTSTR lpName // 指向互斥对象名的指针 ); 申请一个资源 WaitForSingleObject(HANDLE full,INFINITE); 释放资源 ReleaseSemaphore( __in HANDLE hSemaphore,// hSemaphore是要增加的信号量句柄 __in LONG lReleaseCount,// lReleaseCount是增加的计数。 __out_opt LPLONG lpPreviousCount//lpPreviousCount是增加前的数值返回。 ); 释放互斥信号量 BOOL ReleaseMutex(HANDLE hMutex); DWORD WaitForMultipleObjects( DWORD nCount, // number of handles in array CONST HANDLE *lpHandles, // object-handle array BOOL bWaitAll, // wait option DWORD dwMilliseconds // time-out interval );
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值