本文主要内容:

  • 管程(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. curl操作封装

    <?php /** * Class Curl curl简单封装 get post */ class Curl { /** * @brief get请求 * @param $url 请求的url ...

  2. VSCode隐藏node_modules目录

    使用VSCode,打开一个工程时,发现node_modules目录包含到工程中了,问题: settings.json配置如下,可以自己定制忽略的文件夹: search.exclude 用来忽略搜索的文 ...

  3. JavaScript笔记02——基本语法(包括函数、对象、数组等)

    Doing Math & Logic Conditional & Looping Functions Objects Arrays Doing Math & Logic 1.J ...

  4. linux基础三---网络基础&软件包管理

    一 ifconfig:显示所有正在启动的网卡的详细信息或设定系统中网卡的IP地址. ifconfig eno16777736 down/up   关闭/开启 eno16777736 网卡 ifconf ...

  5. [POI2009]Wie

    题目 BZOJ 虽然是解压题但也学到了简洁的码风 做法 \(dijkstra\)跑动规 My complete code #include<bits/stdc++.h> #include& ...

  6. PS小研

    1 ps输入字体不显示原因有很多,解决方法也各不相同,我总结了以下几条原因及相应的解决方法 原因一: 字体颜色和背景色相同或者过于相近,字体虽然存在,但是却看不到字体. 解决方法: 这个问题比较简单, ...

  7. SpringBoot2.0之整合Kafka

    maven依赖: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www. ...

  8. python进阶02

    1.import导入模块 import sys sys.path:显示的是:从显示目录中查找要导入的模块文件. 程序执行时导入模块路径:sys.path.append('/home/itcast/xx ...

  9. [转载]spring security 的 logout 功能

    原文地址:security 的 logout 功能">spring security 的 logout 功能作者:sumnny 转载自:http://lengyun3566.iteye ...

  10. matplotlib画子图时设置总标题

    matplotlib subplots绘图时 设置总标题 :fig.suptitle(name)