文章目录

  • 经典的信号量同步问题
    • 第一部分 生产者消费者问题
    • 1、多生产者多消费者 -- 吃水果
    • 2、单生产者多消费者问题 -- 吸烟者
      • 分析
    • 3、多生产者问题 -- 仓库存货物
      • 分析
      • 解答
    • 4、多生产者-单消费者问题
      • 分析
      • 解答
    • 5、自行车生产线 -- 解决死锁问题
      • 分析
      • 解答
    • 6、多生产者多消费者 -- 消费者连续消费
      • 分析
      • 解答
    • 7、既是生产者 又是消费值
      • 解答
    • 第二部分 营业员 - 顾客问题
    • 1、面包店卖面包问题
      • 分析
      • 解答
    • 2、营业员 -- 顾客问题
      • 分析
      • 解答
    • 第三部分 关于门、路、桥的问题
    • 1、博物馆参观 -- 进门出门问题
      • 分析
      • 解答
    • 2、大桥过车问题
      • 分析
      • 解答
    • 第四部分 哲学家进餐问题
    • 1、哲学家进餐问题1
      • 分析
        • 算法
      • 怎么避免呢?
    • 2、哲学家进餐问题2
      • 解答
    • 第五部分 有趣的生活问题
    • 1、老和尚喝水 -- 小和尚打水问题
      • 分析
      • 解答
    • 2、理发师理发问题⚑
      • 分析
      • 解答
    • 3、放电影问题
      • 分析
      • 解答
    • 4、读者 -- 写者问题
      • 分析
    • 第六部分 结合程序代码分析问题
    • 1、结合线程的同步-互斥问题
      • 分析
      • 解答
    • 2、三个合作进程完成计算操作
      • 分析
      • 解答

经典的信号量同步问题

第一部分 生产者消费者问题

1、多生产者多消费者 – 吃水果

  • 互斥关系

    对缓冲区的访问需要互斥的进行

    消费者与消费者之间为什么有互斥关系呢?因为消费者需要将缓冲区的内容取走,改变了缓冲区的内容。

  • 同步关系

    女儿等待父亲放苹果 儿子等待母亲放橘子

    父亲或母亲等待盘子中的水果被取走 盘子为空才可以放水果 而盘子为空这个事件既可以由儿子触发 也可以由女儿触发 只要触发就可以允许父亲进程和母亲进程放水果

  • 对于缓冲区的个数需要设置同步信号量来标识

    如果缓冲区的数目为1的话,那么同一时刻只会有一个进程访问临界区资源,不会导致互斥问题,有可能不需要设置 互斥信号量 就可以实现 互斥访问缓冲区的功能
    另一个角度:
    同一个时刻只有1个同步信号量的值为1,也就只有一个进程的P操作不会被阻塞,也就实现了进程的互斥

    如果缓冲区大于1的时候,对于多个生产者就需要设置互斥信号量实现互斥的访问临界资源,否则每个生产者进程对临界区的空闲个数进行P操作都可以访问临界区。

  • 分析过程

    • 分析同步问题

      不能从单个进程行为的角度来考虑,而是考虑同步关系事件的先后关系,具体为谁在等待谁释放的什么资源

      对多个消费者 与 多生产者之间的一类(多个)同步关系,并不是每个同步关系对应一个同步信号量, 抽象成 一对事件的先后关系

      比如:

      对单个进程来分析:

      • 儿子取走橘子 导致 父亲可以放苹果

      • 儿子取走橘子 导致 母亲可以放橘子

      • 女儿取走苹果 导致 父亲可以放苹果

      • 女儿取走苹果 导致 母亲可以放橘子

      可以抽象成一对事件的先后关系

      • 取走水果盘子变空事件 导致 放水果事件

      这样就可以使用一个同步信号量来解决问题

2、单生产者多消费者问题 – 吸烟者

分析

完成信号量初始值为0

生产者在生产某一种组合的时候,没有先去等待抽烟者完成,而是先去准备东西,因为最开始是没有人抽烟的,对完成信号量(初始值为0)进行P操作的话会被阻塞。

因此先进行某种组合的V操作,然后对完成信号量进行P操作等待抽烟者取走,如果有抽烟者在抽烟,就进入等待队列,当完成信号量V之后唤醒。

缓冲区信号量初始值1

对上面的解决也可以采用共享缓冲区的数量作为同步信号量,初始值为1

这样生产者每次生产之前先对缓冲区数量进行P操作,代表桌子上没有空位置了,等待抽烟者抽完,对缓冲区信号量进行V操作「类似上面问题的盘子信号量」

3、多生产者问题 – 仓库存货物

分析

  • 进程只有放A产品 进程 和 放B产品进程

  • 关系

    • 互斥:

      每次只能放入一种产品 放A产品和放B产品需要互斥的访问临界资源(仓库)

    • 同步

      这里A放入的时候要考虑 A还能与B是否还能满足数量差(>=0)

      放B之前也要考虑B还能与A容纳的数量差

      设置同步信号量Sa 和 Sb分别代表A 与 B还可容纳的数量差

      放A的进程中

      • 首先要对Sa进行P操作,检查数量差是否还允许A放入

        每次放进去一个A产品,A产品与B产品的数量差就要减一;

      • 当放完之后,要对Sb进行V操作

        为什么呢?

        因为起初A和B产品的数量都是从0开始的,当放入A产品之后,A的产品数量增加了,大于0,受Sa的影响只能放入有限的A产品,然后Sb代表的是相对于A来说允许的差量值,应该是对A现在产品数量再加上Sb的值,但是B产品起初是0,如果B产品放之间对Sb进行P操作,这样只是假设在A产品0件的基础上进行放B产品,因此需要在A产品放入之后,对B与A之间容纳的差量值Sb也要进行V操作,此时Sb变大了,当B产品一直放当追上A产品数量之后,就按照初始的N值进行放B产品,实现相对于A当前数量进行放B产品「在可容纳的差量值之前」

        实际上,B产品在追上A产品数量之前,是由A与B的差量值M控制的「因为此时A已经比B多m-1件了,达到允许的差量最大值,便不再放A,但是B可以放呀,B放之后,对Sa进行V操作,又唤醒了放A产品的进程,因为B产品的放入仓库,导致A与B之间的实际差量值又小于可容纳最大差量值M了,所以A又可以愉快的放入库中了」,追上之后按照B与A的差量值(N)进行控制

解答

4、多生产者-单消费者问题


分析

  • 进程

    这里有三个进程:

    • 生产车间生产A产品并放入F1货架的进程
    • 生产车间生产 B产品并放入F2货架的进程
    • 装配车间分别从货架F1和货架F2上取得A、B零件组装产品进程
  • 关系

    • 互斥

      这里货架属于互斥缓冲区资源,在放入零件和取出零件的时候不允许两个进程同时访问货架临界区资源,防止它们对货架上的同一个位置放零件,这是不允许的。

      因此需要设置mutex对货架进行互斥的访问

    • 同步

      这里放零件A到货架上的进程需要等待组装进程取走货架上的零件而产生的空闲位置
      而组装进程需要等待放零件进程放入货架之后充满一个位置

      因此需要对F1货架的A零件和货架F2的B零件分别设置empty(=10)和full(=0)同步变量来记录货架缓冲区是否为空,是否未满

解答


5、自行车生产线 – 解决死锁问题

分析

这里的问题与前面的多生产者单消费者问题类似,不同的地方在于前面的多生产者生产的东西不是放到同一个缓冲区资源里,因此即使第一个生产者将货架放满了,生产者2还是可以生产放入另一个货架的,这样消费者就可以从各个货架分别取零件然后第一个生产者进程就被唤醒了。

这里是将不同生产者的零件都放到同一个箱子里,这个箱子就是互斥临界资源,当第一个生产者的零件充满临界资源之后就需要等待消费者取走几个零件然后唤醒此进程,但是此时生产者2因为箱子无空间无法生产零件,导致消费者无法取得生产者2生产的零件而被阻塞,这样3个进程权都被堵塞而互相等待,这就产生了死锁。因此不能让某个生产者一直生产零件而占满互斥缓冲区。

  • 进程

    2个生产者进程 1个消费者进程

  • 关系

    • 互斥

      这里应该对袋子的访问是互斥进行的,但是只有一个放和取的操作,没有检测与设置这样分开的动作,因此可以不用设置互斥信号量

    • 同步

      生产者1 和 生产者2 都需要等待袋子是否有空闲空间来存放自己的零件,除此之外,还要判断袋子中自己的零件是否达到了最大值(防止形成死锁)

      消费者需要等待生产者生产的零件而进程组装。

    • 信号量

      empty = N 标识袋子中剩余空间

      wheel = 0 标识生产的零件的数目

      frame =0 标识生产的 车架的数目

      s1 = N -2 车架可以生产的最大数目,要至少生产2个车轮放在袋子中,防止死锁的产生

      s2 = N -1 车轮的最大数目,至少生产1个车架防止袋子中

解答



6、多生产者多消费者 – 消费者连续消费

分析

这里和典型的生产者 - 消费者问题类似 ,只是增加了消费者在消费的时候需要从缓冲区中连续取走10件产品之后才允许其他消费者进程去消费

  • 关系

    • 互斥

      消费者 必须 等待前一个消费者进程取走10件产品 ,连续取10件产品这个过程是不可以被打断的,因此设置互斥变量mutex_1来控制,

      消费者进程 与 生产者进程对缓冲区的访问需要互斥的进行,因此设置互斥变量mutex_2来控制

    • 同步

      生产者等待消费者从缓冲区中取走产品产生空闲, 设置信号量 empty = 1000

      消费者等待生产者向缓冲区中放入产品, 设置信号量 full = 0

解答



key

这里可以借鉴的是,消费者需要不被中断的连续取10次,可以采用for循环,在每一个循环题内部进行一系列的取产品操作,每一次取也要互斥的访问临界区,每当取完10次的时候才会释放mutex_1临界区,当其他消费者进程想要取产品的时候会被阻塞到mutex_1的等待队列中

7、既是生产者 又是消费值

解答


第二部分 营业员 - 顾客问题

1、面包店卖面包问题

分析

  • 进程

    这里只有顾客进店取号进程,取完之后就等待被叫号买面包

    因此还有服务员叫号卖面包进程

  • 关系

    • 互斥

      这里貌似没有互斥关系,只有同步关系

    • 同步

      服务员要等待当前有人取号在等待叫号才可以成功(实际生活中只有取了号,服务员那里才可以叫到,否则进程应该被阻塞,因为叫到了还没被取的号)

      而顾客不需要等待服务员叫走前面的号才可以取号,顾客可以一直取号而不用关心服务员怎么叫到自己或者什么时候叫到自己

      • 这里服务员在叫号,顾客在取号的时候,这两个过程应该是不能被其他叫号、取号进程打断或同时进行的,否则会出现两个进程同时访问号子,如果是最后一位顾客,导致对叫到的号进行if检测都可以通过,但是只有一个进程完成叫号操作并对叫得号执行++操作,这位顾客已经完成买面包走了,这时候另一个进程还在等待这个顾客造成死等现象。

        因此就需要对顾客取号(i的访问和修改)、服务员的叫号(j的访问和修改)分别设置互斥信号量mutex_i、mutex_j 实现互斥地访问和修改i、j,保证一个人在没取完号的时候,另一个顾客不允许取号。

      • 实际生活中,一天从早到晚号码是一直增加的,顾客那有号子序列,服务员那也有号子序列(总是小于等于顾客的号码),因此设置共享变量i、j来进行控制号码的修改。

        这里的 i 和 j 就是临界资源,需要互斥的访问(不能两个顾客同时取一个号、也不能两个服务员同时给一位顾客服务)

  • key

    这个题目可以借鉴的地方是:本身没有互斥关系,但是对号子的访问和修改需要互斥的进行,需要设置互斥变量来控制

解答


2、营业员 – 顾客问题


分析

  • 这里与前面的卖面包的问题不同的是,顾客来了之后就直接取号等待被叫号,而是有空闲座位,当没有空闲座位的时候就不能取号了,只能在门外等待。

    而且在取了号子之后就坐在座位上排队等待在营业台的客户完成服务,这里营业员不再按号码叫号了,而是简单的检查是否有客户在座位上等待服务,有的话就让他到服务台来给予服务,这样就让出一个空闲的排队等待座位,服务完毕就置服务台为空。

    总的来说这里营业台只有1个,排队座位有10个,不像卖面包的客户不需要作座位,销售人员按号子进行叫号。

  • 进程

    客户取号子请求服务进程

    营业员给予服务进程

  • 关系

    • 互斥

      客户在取号的时候对取号机需要互斥的访问 设置互斥信号量mutex实现

    • 同步

      顾客在进入银行的时候要先判断有没有空位置 设置信号量empty = 10

      取了号之后坐在座位上等待要通知营业员有新客户 设置信号量 full = 0

      然后就等待营业员提供服务 **设置信号量service = 0 **

解答


第三部分 关于门、路、桥的问题

1、博物馆参观 – 进门出门问题

分析

  • 进程

    这里只有参观者进程

  • 关系

    • 互斥

      这里门是互斥资源,一次只允许一个人进入、或出来,因此设置mutex控制互斥的进出门

    • 同步

      这里博物馆最多可以容纳500人在里面,因此共享资源的数目就是500, 每次进去之前要判断是否还可以进去,里面人满了进不去了,就需要阻塞参观者进程

解答

2、大桥过车问题

分析

这个问题的第一问其实就是博物馆参观问题,但是这里的第二问是变体,同一个方向的车允许通过,也就是同一个方向上只要有车,那么就可以直接上桥而不需要申请访问互斥资源–大桥,因此又很像读者 – 写者问题。

  • 进程

    这里包括两个进程

    • 从南向北的车的进程
    • 从北向南的车的进程
  • 关系

    • 互斥

      不同方向的车要上大桥需要互斥的进行,同一个方向的车连续上桥不需要等待访问控制权

    • 同步

      这里需要解决的就是怎么控制第2个以及后续的同一方向的车不需要对大桥的访问权进行申请

  • 信号量

    设置mutex控制不同方向上的车上桥

    设置同一方向的车的计数变量count来记录当前方向的车前面是否有同样方向的,每个车上桥之前先检测判断count是否 = = 0,不是的话直接count++ 操作然后上桥,但是存在潜在问题,如果两个车同时上桥都通过count检测,然后第一个要进行P(mutex)没错,但是此时第2个进程已经通过了count ==0 的if检测,仍需要进行申请上大桥,所以就不符合题目要求了。

    问题出在哪儿呢?

    就是因为对count变量的访问以及修改没有一气呵成而且还与其他进程并发执行,导致第一个进程还没有count++的时候,第二个进程就已经通过了if检测,导致后面的错误。因此需要设置额外的互斥信号量mutex_1来对count变量实现互斥的访问,这样就实现了后面的车进程就会等待第一辆车上桥完整修改count值之后再取检测count值,这样count已经=1,不会在进行P(mutex)操作

    「注」当最后一个同方向的车下桥之后也就是count重新变为0,就需要进行V(mutex)操作,另一个方向的车进程就可以被唤醒了

解答


第四部分 哲学家进餐问题

1、哲学家进餐问题1


分析

  • 关系分析

    5个哲学家进程

    每个哲学家与左右两个哲学家进程之间的筷子的拿起存在互斥的关系

    只存在互斥关系,每一个哲学家进程必须拿起两个临界资源才可以正常的执行吃饭时间【与之前的问题不同的地方】,对临界资源分配不当的话会导致死锁现象。

  • 信号量设置

    一共5个筷子都是临界资源,设置数组chopsticks [5] ={1,1,1,1,1 }

    并对哲学家进行编号 0- 4

算法


简单的对互斥信号量进行PV操作

但是当多个进程可以并发执行的时候,每个哲学家都拿起了自己左手边的筷子,都被右边筷子的互斥信号量阻塞,造成循环等待右边的进程释放筷子来唤醒它,产生了“死锁“ 的现象 – 每个进程都在阻塞的等待对方持有的资源,自己又不会主动的释放(占有并请求)

怎么避免呢?

这样即使这些哲学家进程并发的执行,每一个哲学家都拿起了一只筷子,但是最后总会剩下一只筷子可以分配给相邻的哲学家进行正常的吃饭,当它吃完饭之后放下筷子,其他哲学家又会依次被激活。

这样可以保证至少有一位哲学家可以拿到两只筷子的从而避免死锁。

算法:设置初始值为4的信号量

这样改变了哲学家进程拿筷子的顺序,不是按照先左后右的顺序进行拿筷子,导致某一个哲学家在没有拿这筷子的情况下也会被阻塞(打破了占有且保持)

算法:每一个哲学家拿筷子之间判断哲学家的序号是奇数还是偶数

算法:

保证第一个拿筷子的进程可以不被中断的取完两只筷子,这样尽管后面的进程可能会被阻塞,但是第一个哲学家进程可以完整的执行完吃饭过程。

而且当一个哲学家因为取一只筷子被阻塞之后,此时mutex变为0,后面的哲学家会被mutex阻塞到等待队列,直到前一个进程取完筷子执行V(mutex)唤醒后面的哲学家进程让其开始取筷子。

这样就保证了同一时刻只会有一个哲学家进程在完整的进行取筷子进程,一个哲学家没拿完就不会允许其他哲学家进程开始拿筷子操作。这样就不会导致循环等待而产生死锁现象。

保证了总会有一个哲学家持有两只筷子可以进行吃饭操作,对筷子的释放可以唤醒其他阻塞进程。

2、哲学家进餐问题2

解答


第五部分 有趣的生活问题

1、老和尚喝水 – 小和尚打水问题

分析

  • 进程

    这里有小和尚打水的进程(包括从井里打出水再注入缸里)

    还有老和尚从缸里喝水的进程(这两个进程要完成的操作都需要用到桶)

  • 关系

    • 互斥

      水缸径窄,每次只能容一个桶打水,因此小和尚打水的时候对井是互斥访问

      每次入缸取水入水都是1桶水,因此小和尚与小和尚之间注水、小和尚注水与老和尚喝水、老和尚与老和尚之间喝水都要互斥进行

    • 同步

      水缸总共可容纳10桶水,因此小和尚打水之前先要判断缸里是否还有容量可以注水,

      水桶总共有3个,小和尚打水 和 老和尚取水之前要先判断是否还有桶处于空闲

      老和尚取水之前需要判断缸里有水没

    • 信号量

      well = 1对井互斥访问
      vat = 1 对水缸互斥访问

      empty = 10 表示水缸 剩余空间能容纳的 水的桶数
      full = 0 水缸中水的桶数
      pail = 3 表示多少个水桶可以用

解答


2、理发师理发问题⚑

分析

这个问题与营业员 – 顾客问题类似,但又不尽相同

  • 进程

    顾客进程 和 理发师进程

  • 关系

    • 互斥

    • 同步

      当理发师正在理发的时候,顾客进入检查是否有空位置而坐下来等待;若没有在理发,那么就要唤醒理发师进程;「顾客要等待理发师醒」

      当理发师理发之前,等待顾客,有人在等待就工作唤醒顾客等待进程,否则睡觉;「理发师要等待顾客来」

    • 信号量

      waiting = 0 店里可容纳的顾客数目有限,记录等待的顾客数目,进来一个+1,理完一个-1

      costomers = 0 记录等候理发的顾客数,用来阻塞理发师进程

      barbaers =0 用来记录等待 顾客的理发师数 , 用作阻塞用户进程

      mutext = 1用来互斥的访问并修改变量waiting

解答



KEY

这个题目可以借鉴的地方,设置V(costormers)来唤醒理发师进程,然后顾客进程执行P(barbers)被阻塞,(如果现在理发师在睡觉),理发师醒了之后对一个等待的人进行理发,进行V(barbers)操作意思为可以对顾客理发了,唤醒了顾客进程进行理发。

3、放电影问题

分析

因为每种观众只看自己喜欢的电影,不是自己喜欢的电影就等待,电影院对某个电影直到观众全都看完,最后一个走的时候才结束播放这个电影,换下一个电影播放,因此要设置一个变量记录观众的数目。

  • 关系

    • 互斥

      前面分析用计数器count来记录观众的数目,因此对计数器的访问或者修改都需要互斥的进行,设置互斥变量实现

    • 同步

      当观众进入电影院观看电影之前互斥的对观众数目count进行检测和更新+1,如果是第一个观众的话,就需要等待互斥资源 – 电影,「如果还没放就阻塞等待,放了就进入电影观看」

      看完影片之后,要对当前电影的观众数目进行更新,此处需要互斥的进行,直到最后一位观众看完,需要退出互斥临界区 – 电影

    • 信号量

      设置三个计数器count1 count2 count3 初始值为0 来记录观众的数目

      为了互斥的访问这三个技术值 设置互斥信号量 s1 s2 s3初始值为1

      观看每种电影的第一位观众需要对电影包房临界资源进行申请,所以这只互斥信号量S = 1 别的类型观众(第一位)在进入电影院的时候申请包房观看电影就会被阻塞,已经被别的类型观众包了,得等它们全部观看完电影才会退出包房 – 释放临界资源

解答



【注 : 题目解答分析有点错误(我觉得:)】

4、读者 – 写者问题

分析

  • 互斥关系

    写进程-写进程

    写进程-读进程

    每一对互斥关系都需要一个互斥信号量表示 一次只允许一个进程互斥访问此文件

    • 互斥关系1

      由上面可知 对于这个共享文件 写进程与其他所有进程都存在 互斥关系

      设置互斥信号量 rw 表示当前是否有进程在访问共享文件 ,初始值为1,0 表示有进程在访问文件

      在写进程访问共享文件前后进行PV操作

      读进程在访问共享文件之前也要对互斥变量rw进行 PV操作

    • 非互斥关系2

      读者与读者之间是没有互斥关系的,通过上述互斥信号量rw

      如果每个读者在访问共享文件之前都对rw进行P操作,那么当一个读进程在读的时候,另一个读进程会被堵塞至rw的等待队列 , 无法实现两个读进程同时访问共享文件的问题

      怎么实现呢?

      应该让第一个读进程对共享文件进行加锁, 第二个读进程检测到有进程在读文件,就直接进程读文件;当最后一个进程读完文件之后,就绪要解锁,让写进程访问共享文件。

      设置int变量count标识当前读进程的个数,初始值为0
      用if语句检测是否是第一个读进程,如果是的话, 对文件加锁操作,然后count++,进行读取文件

      下一个读进程直接进行读取文件内容。

      读完文件内容之后,count执行–操作,用if语句检查是否是最后一个进程,如果是的话,就需要对共享文件进行解锁操作。

      存在问题

      如果两个读进程并发执行,都经过了if检测,然后进行P(rw)操作,导致后面那个读进程被阻塞。
      问题的原因就在于,count的检测和count++ 并不是一气呵成的

      因此需要对count变量的访问互斥的进行,在if执行完之后没有执行count++之前不允许其他读进程对count进行if检测

      通过设置互斥变量mutex = 1来保证各个读进程对count的访问是互斥的,对count访问之前和之后都需要PV操作

      潜在问题

      如果此时有一个进程在读文件,而且需要读的时间很长,此时如果有源源不断的进程接连到达,那么写进程就会被阻塞且一直在等待,导致饥饿现象(因为第一个读进程没有释放共享文件)因此这种算法是读优先的。

      另一个角度分析:

      因为接连到达的读进程如果对mutex进行P操作的时候被堵塞的话也是被送到mutex.L阻塞队列中,当前面的读进程访问完count之后就可以从mutex的阻塞队列中唤醒一个读进程放入就绪队列,之后就可以按照FCFS的原则进行调度执行读操作,这个速度是很快的(或者时间慢点,但是总会比下面写进程被唤醒然后参与调度要早)

      但是写进程就不一样了,因为它是被P(rw)操作阻塞的,此时有很多读进程在读,等到所有读进程读完释放共享文件执行V(rw)操作才会唤醒写操作,这需要很长时间,因此就会导致饥饿现象,长时间处于阻塞队列,甚至会导致很多写进程都被阻塞而送到阻塞队列,严重影响写进程的执行效率。

      怎么修改为写优先

      再增加一个互斥信号量w,让所有的进程,不管是读进程还是写进程,在进行访问互斥资源–共享文件之前都需要对w执行P操作,

      如果当前有一个读进程在运行,完成了P(w)、P(mutex)、V(mutex)、但是还没有执行V(w)操作,因此第二个读进程就会被阻塞送到w的阻塞队列,如果接着又来了一个写进程,那么这个进程也被w阻塞,因为第一个进程还没有释放w。这样当第一个读进程执行了V(w)之后,第二个读进程与写进程同属于w的阻塞队列,第2个读进程处于对首先被唤醒送入就绪队列,然后参与调度执行。第个读进程在执行的过程中,这个时候如果再来其他的读进程,首先会被w互斥变量阻塞到与写进程同样的等待队列,此时写进程处于对首的位置,当第2个读进程执行了V(w)操作之后,写进程被唤醒送到就绪队列进而等待调度执行下一步P(rw)操作。

      再举一个例子:

      如果以读进程在进行读操作,且完成了V(w)操作,然后接着来了一个写进程和读进程,写进程执行完P(w)操作,然后被互斥信号量rw阻塞进入rw的等待队列,接着读进程又被w阻塞进入w的等待队列(这里只能被前一个写进程执行完写操作之后的V(w)唤醒),这样就决定了写进程执行不了,读进程永远也唤醒不了。因此实现了写优先。

      这里与上一个算法不同的地方在于:后续的读进程与写进程都是被互斥变量w堵塞而进入w等待队列,等待唤醒是按在队列中的先后位置决定的。不像前面算法写进程与读进程不在同一个等待队列,自然被唤醒的时机也不一样。

      关键

      在于不同的互斥信号量会有不同的等待队列,不同的进程会被不同的互斥信号量阻塞,导致被唤醒的时机不同。

      总结

      修改后的算法严格意义上不是绝对的写优先,因为当有一个写进程运行的时候,接连来了读进程和写进程,这两个进程都会被阻塞到w等待队列,然后按照在等待队列的位置按顺序被唤醒,不像读优先那样,只要有读进程在读,后面的直接就可以读。这里写进程还是会和读进程公平的竞争共享文件,因此又叫读写公平法。



第六部分 结合程序代码分析问题

1、结合线程的同步-互斥问题


分析

  • 对共享变量是否存在互斥关系 :

    如果两个进程对同一个变量同时存在读 和 写 或者 写和写 那么就是互斥关系 读与读之间不存在互斥关系

    「这里 线程1的y 与线程3的y 以及 线程2 的y 与 线程3的y分别存在互斥关系,不是3个y存在两两互斥关系 ,因此 对每一对互斥关系都需要设置一个互斥变量 线程2的z与线程3的z也存在互斥关系,因此也需要设置互斥变量来控制」

  • 对共享变量的同步

    这里的全局变量都属于临界资源,没有等待产生的结果,因此主要是互斥关系

解答

2、三个合作进程完成计算操作

分析

  • 进程

    进程就如题所示:P1、P2、P3三个合作进程。每个进程都有输入操作和计算操作

  • 关系

    • 互斥:

      在使用输入设备输入数据的时候需要互斥输入,有互斥关系,但是可以通过同步信号量解决(因为1个进程只输入一次而不是多次访问输入设备这个互斥资源,而且是按照顺序a、b、c依次输入)

    • 同步:

      更多是前驱同步关系

      比如:P1输入数据a,然后P2进程需要使用a;P2计算得到y,而P3计算需要y;P1最后要打印输出x,y,z的值,需要P2的y和P3的z

      而且题目要求三个进程在输入各自数据的时候输入设备互斥的使用,按顺序输入3个数据,因此需要设置3个信号量S1、S2、S3以控制3个进程依次输入各自的数据。S1最先输入,初始值为1,「同步信号量不总是初始为0,而是与其他同步信号量成对使用,总是能保证有一个信号量不为1防止进程都被阻塞」
      P1进程输入数据结束之后就对S2进行V操作唤醒P2进程进行输入数据操作,接着P2进程输入完数据之后对S3进行V操作唤醒P3进程进行输入数据。

    • 信号量

      除了上面的用于进程输入数据的S1、S2、S3同步信号量,还需要设置P1进程等待b、P3进程等待数据y、P1进程等待数据y和z,因此设置

      Sb =0 标识数据b是否已经输入

      Sy = 0 Sz=0 标识数据是否已经计算完成

      为什么这些信号量的初始值都为0呢?

      因为起初都没有被计算或输入,但是前面的S1初始值为1,因此P1进程中的操作可以一一唤醒后面的操作按序进行,不必担心不被唤醒。

解答


【注】

P2进程中有两个V(Sy)操作是因为P2进程完成y的计算之后一方面要唤醒P3 对z计算前的P(Sy)的阻塞进程,另一方面是唤醒在进程P1中打印输出y的P1阻塞进程

题目来自王道考研-操作系统,部分截图来自王道b站放出的视频,纯属个人见解,「复习用」。有错误欢迎留言,免得我误入歧途。

操作系统 之 「信号量机制解决进程同步问题」相关推荐

  1. 操作系统之进程管理:11、用信号量机制实现进程同步、互斥、前驱关系

    11.用信号量机制实现进程同步.互斥.前驱关系 思维导图 用信号量机制实现进程同步 用信号量机制实现进程互斥 用信号量机制实现进程的前驱关系 思维导图 用信号量机制实现进程同步 先来看一下什么是进程同 ...

  2. 使用信号量机制解决生产者消费者问题

    生产者消费者问题是经典的同步问题,这篇文章用来记录一下如何使用信号量机制解决. 信号量机制(Semaphore)是解决同步问题常用解法,所谓信号量其实就代表着对应共享资源的数量.对于信号量只允许三种操 ...

  3. 卡住无法查看到所有进程_进程同步 进程互斥 软件和硬件实现方式 信号量机制 信号量机制实现进程同步,进程互斥,前驱关系...

    参考:https://www.bilibili.com/video/av31584226/?p=9 进程具有异步性的特征,异步性是指,各并发执行的进程以各自独立的,不可预知的速度向前推进. 回忆我们之 ...

  4. 【操作系统·考研】信号量机制/PV操作

    在操作系统引入进程后,一方面,系统中的多道程序可以并发执行,不仅有效改善资源利用率,而且显著提高系统的吞吐量.另一方面,如果不对多个进程的运行进行妥善管理,必然会因为这些进程对系统资源的无序争夺给系统 ...

  5. 【操作系统原理】信号量机制

            信号量机制是一种卓有成效的进程互斥同步工具.这里只介绍记录型信号量机制,它可以有效的解决CPU"忙等"的问题,实现互斥.          记录型信号量机制的数据结 ...

  6. 信号量哲学家问题java_利用AND信号量机制解决哲学家进餐问题

    哲学家就餐问题是1965年由Dijkstra提出的一种线程同步的问题. 问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条.哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿 ...

  7. 操作系统 # 从零开始的信号量机制理论与实践

    copyright© skysys 未经授权,禁止转载.原文发布于CSDN:skysys.blog.csdn.net 编程实现使用DevCpp 运行环境为Windows系统 完成这个实验需要自学&qu ...

  8. 【操作系统】进程管理(五)—— 信号量机制

    [操作系统]进程管理(五)-- 信号量机制 前言 一.信号量机制 信号量机制--整型信号量 信号量机制--记录型信号量 二.用信号量机制实现进程互斥.同步.前驱关系 信号量机制实现进程互斥 信号量机制 ...

  9. 操作系统(二十二)用信号量机制实现进程互斥、同步、前驱关系

    2.3.5 用信号量机制实现进程互斥.同步.前驱关系 目录 2.3.5 用信号量机制实现进程互斥.同步.前驱关系 2.3.5.1 用信号量机制实现进程互斥 2.3.5.2 用信号量机制实现进程同步 2 ...

最新文章

  1. DGL RDKit | 基于Attentive FP可视化训练模型原子权重
  2. 超详细解读Java接口:模块通信协议以及默认方法和静态方法
  3. 中石油大学计算机二在线作业答案,中国石油大学计算机应用基础第二阶段在线作业答案2018年.doc...
  4. html 超链接 ppt,HTML超链接要点.ppt
  5. 图论--拓扑排序--判断是否为DAG图
  6. 【招聘(上海)】 坚果云 招聘Windows客户端(WPF方向)
  7. 阿里巴巴 DevOps 工具体系
  8. linux内核调度 0号进程,Linux内核源代码情景分析---第四章 进程与进程调度
  9. C++ 通讯录设计(一)
  10. shell脚本七十问
  11. 生物信息 Python 库 - Dash Bio 究竟厉害在哪里?
  12. 用python如何制作表格步骤_Python中用xlwt制作表格实例讲解
  13. android 坚挺通话广播_关于短信黑名单 BroadCast
  14. 【知识分享】常见的Kepware冗余功能介绍
  15. 解决allwinner bootlogo.bmg 开机logo 修改 后变绿
  16. mac电脑运行速度变慢的十种解决方法
  17. xp升级到win7傻瓜教程_MeGUI教程-软件环境配置(转)
  18. 2020 知来者之可追
  19. 7-22 循环日程表
  20. 天津大学大学计算机基础成绩查询,天津大学《大学计算机基础1》课程教学大纲.PDF...

热门文章

  1. SqlServer: 汉字转拼音标量函数
  2. android 数据存储的几种方式
  3. 浅析Vue中ref属性与getElementById的区别
  4. [LGCN论文笔记]:Large-Scale Learnable Graph Convolutional Networks
  5. 图片重命名,命名方式为:文件夹名字 + _ 顺序 + .jpg
  6. 计算机ps作品大赛奖品,全国创新杯说课大赛计算机应用基础类一等奖作品:ps动态图像制作说课课件...
  7. .NET平台框架解读
  8. 2018年7月16日训练日记
  9. springmvc返回JSP源码
  10. H3C路由器 basic NAT典型组网配置