本文主要内容:

  • 管程(Monitor)介绍
  • 管程实现
  • 管程应用

一、管程(Monitor)介绍

1.1 管程

前一篇文章介绍了信号量以及使用,信号量已经提供了一个方便且高效的进程同步机制,但是信号量有个缺点就是每次都需要程序员专门的去调用PV操作,如果程序员由于大意调用错了PV操作,比如该调用P操作的时候却调用了V操作,该针对X信号量调用P操作,却对Y信号量调用了P操作。这种错误是非常危险的,因为进程同步的问题不是每次都能重现,比如前面的错误在测试环境可能不会出现错误,但是到了生产环境就有可能出现,且无法重现。

为了解决上述问题,引入了管程(Monitor),信号量是操作系统层面的结构,管程是一个程序结构,由编程语言封装,最终由编译器:

  • 一个管程定义了一个数据结构和能够并发进程所执行的一组操作,这组操作能同步进程和改变管程中的数据
  • 进程可以调用管程的操作,但是不能访问管程的内部数据结构
  • 它表示一个对象自己维护自己的状态,并且能够根据自身状态来同步并发的线程操作,而不是把这种同步的手段交给调用者来处理。
  • 管程保证同一时间只有一个进程处在管程内部的方法内
monitor MonitorName
{
//shared variable declarations
procedure P1(...)
{ }
procedure P2(...)
{ } procedure P3(...)
{ } procedure PN(...)
{ } initialization code(...)
{ }
}

1.2 条件(Condition variables)

只有管程是不够的,在生产者消费者的例子中,当发现buffer中如果已经没有item的时候,消费者如何block自己呢?介于这个原因,又引入了条件变量(Condition Variables)。条件变量同时提供了两个方法:P以及V用于block和unblock。

二、管程实现

管程通过队列来跟踪那些尝试着想访问管程的进程,为了排他访问,管程必须得有一个锁,访问管程的进程会得到这个锁,其他尝试访问管程的进程就得block。被block的进程会被放入队列,等待被unblock。

管程的实现中有如下的队列:

  1. 进入队列(Entry Queue),保存尝试从外部访问管程程序的进程,每个管程至少有一个进入队列
  2. 被唤醒的队列(Signaller Queue),保存刚刚执行了V操场的进程(signal)
  3. 等待队列(Waiting Queue),保存刚刚被V操作唤醒的进程
  4. 条件变量队列(Condition Variable Queue),保存刚刚执行了条件变量Wait(P)操作的进程

三、管程应用

上一篇文章针对哲学家用餐给出的解决方案有个问题:当所有哲学家同时拿起筷子想吃饭的时候就会发生死锁,所有哲学家都会一直处于等待状态。本文用管程给出了解决方案,哲学家吃饭得满足的条件:

  1. 哲学家饿(hungry)
  2. 哲学家的左右邻居都没有吃饭

如果满足上面条件,则哲学家便可以拿起筷子进行用餐,否则哲学家就得等待

monitor dp
{
enum {thinking, hungry, eating} state[];
condition self[]; void pickup(int i) {
state[i] = hungry;
test(i);
if (state[i] != eating)
self[i].wait();//P操作
} void putdown(int i) {
state[i] = thinking;
test( (i+)% );
test( (i+)% );
} void test(int i) {
if ((state[(i+)%] != eating) &&
(state[i] == hungry) &&
(state[(i+)%] != eating)) {
state[i] = eating;
self[i].signal();//V操作
}
} void init() {
for (int i = ; i < ; i++)
state[i] = thinking;
}
}

Condition Self代表五个哲学家,当不能吃时候进行wait。

db.pickup(i);//找筷子
...
eating//吃
...
dp.putdown(i);//放下筷子

管程更多的是对资源的并发访问做了一次封装,感觉有很多OO编程的思想,直接用信号量的话,各种控制会很发散,当然容易出错,信号量本事是没有问题的。但是使用容易出错。且由于散发在多出,出问题不好排查,也不好修复。

管程是一种编程思想,这种思想就是封装,并且有DRY的感觉。

Operating System-进程/线程内部通信-管程(Monitor)介绍,实现以及应用的更多相关文章

  1. 突破python缺陷,实现几种自定义线程池 以及进程、线程、协程的介绍

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python # -*- coding:utf-8 -*- import t ...

  2. python进程.线程和协程的总结

    I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...

  3. python系列7进程线程和协程

    目录 进程 线程 协程  上下文切换 前言:线程和进程的关系图 由下图可知,在每个应用程序执行的过程中,都会去产生一个主进程和主线程来完成工作,当我们需要并发的执行的时候,就会通过主进程去生成一系列的 ...

  4. Python 进程、线程、协程的介绍与使用

    一.必备的理论基础 二.操作系统发展史 三.进程理论 四.线程理论 五.协程 一.必备的理论基础 操作系统理论: 操作系统是一个协调\管理\控制计算机硬件资源与应用软件资源的控制程序 操作系统的两大功 ...

  5. 进程线程协程补充、docker-compose一键部署项目、搭建代理池、requests超时设置、认证设置、异常处理、上传文件

    今日内容概要 补充:进程,线程,协程 docker-compose一键部署演示 搭建代理池 requests超时设置 requests认证设置 requests异常处理 requests上传文件 内容 ...

  6. Linux查看进程线程个数

    1.根据进程号进行查询: # pstree -p 进程号 # top -Hp 进程号 2.根据进程名字进行查询: # pstree -p `ps -e | grep server | awk '{pr ...

  7. Python之路第一课Day9--随堂笔记之二(进程、线程、协程篇)

    本节内容 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Queu ...

  8. Python之路,Day9, 进程、线程、协程篇

    本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者 ...

  9. Python学习之路--进程,线程,协程

    进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Q ...

随机推荐

  1. C++ IPv4与IPv6的兼容编码(转,出自http://blog.csdn.net/ligt0610/article/details/18667595)

    这里不再对IPv6 socket相关编程的基础知识进行讲解,只提供一个IP协议无关的服务端和客户端的代码,仅供参考. 服务端代码: #include <iostream> #include ...

  2. 【leetcode刷题笔记】Number of 1 Bits

    Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also know ...

  3. 在Java中调用Python代码

    极少数时候,我们会碰到类似这样的问题:与A同学合作写代码, A同学只会写Python,不熟悉Java ,而你只会写Java不擅长Python,并且发现难以用Java来重写对方的代码,这时,就不得不想方 ...

  4. cocos2dx打飞机项目笔记三:HeroLayer类和坐标系

    HeroLayer类主要是处理hero的一些相关东西,以及调用bulletLayer的一些方法,因为子弹是附属于hero的~~ HeroLayer 类的成员如下: class HeroLayer : ...

  5. C++逗号表达式

    c++中,逗号表达式的结果是最右边表达式的值

  6. Why does typeof array with objects return “Object” and not “Array”?

    https://stackoverflow.com/questions/4775722/check-if-object-is-an-array One of the weird behaviour a ...

  7. 使用UNIDAC连接oracle时的参数设置

    在uniconnection1里设置: server项位hostip:port:sid,如10.53.x.XX:1521:or10g 然后在Options里设置: charset:utf8 direc ...

  8. [BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏

    题意:俩智障又在玩游戏.规则如下: 给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全 ...

  9. django学习笔记整理(1)django的MTV模式

    django作为一个python的网络编程的框架,自然有着其规律可循.通过对django的了解,也明白了一些网络编程的知识.最近这近一个月,在网上查了许多文字资料,也看了别人的视频之类的资料,也算是对 ...

  10. hdu 5890 Eighty seven 暴力+bitset优化背包

    Eighty seven Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) P ...