The Producer-Consumer Problem

Presenter Notes:

  生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

  要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

代码:

#define N 100                /* number of slots in the buffer */
semaphore mutex = ; /* controls access to critical region*/
semaphore empty = N; /* counts empty buffer slots */
semaphore full = ; /* counts full buffer slots */ void producer(void) {
int item;
while (TRUE) {
item = produce_item();
P(empty);
P(mutex);
insert_item(item);
V(mutex);
V(full);
}
}
void consumer(void) {
int item;
while (TRUE) {
P(full);
P(mutex);
item = remove_item();
V(mutex);
V(empty);
consume_item(item);
}
}

Dining Philosophers Problem

Presenter Notes:

  哲学家就餐问题是在计算机科学中的一个经典问题,用来演示在并行计算中多线程同步(Synchronization)时产生的问题。在1971年,著名的计算机科学家艾兹格·迪科斯彻提出了一个同步问题,即假设有五台计算机都试图访问五份共享的磁带驱动器。稍后,这个问题被托尼·霍尔重新表述为哲学家就餐问题。这个问题可以用来解释死锁和资源耗尽。

  哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。 哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。

#define N 5
#define LEFT (i+N-1)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATTING 2
int state[N]; /* array to keep track of everyone's state */
semaphore mutex=; /* mutual exclusion for critical regions */
semaphore s[N]; /* one semaphore per philosopher */ void philosopher(int i)
{
while (TRUE) {
think(i);
take_forks(i);
eat();
put_forks(i);
}
}
void take_forks(int i)
{
P(mutex)
state[i] = HUNGRY;
test(i);
V(mutex);
P(s[i]);
} void put_forks(int i)
{
P(mutex)
state[i] = THINKING;
test(LEFT);
test(RIGHT);
V(mutex);
}
void test(int i)
{
if( state[i] == HUNGRY
&& state[LEFT] != EATTING
&& state[RIGTH] != EATTING) {
state[i] = EATTING;
V(s[i]);
}
}

The Readers and Writers Problem

Presenter Notes:

  有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:

  ①允许多个读者可以同时对文件执行读操作;

  ②只允许一个写者往文件中写信息;

  ③任一写者在完成写操作之前不允许其他读者或写者工作;

  ④写者执行写操作前,应让已有的读者和写者全部退出。

分析思想:

  读者到: 1)无读者、写者,新读者可以读

       2)有写者等,但有其它读者正在读,则新读者也可以读

       3)有写者写,新读者等

  写者到: 1)无读者,新写者可以写

       2)有读者,新写者等待

       3)有其它写者,新写者等待。

Reader priority solution

semaphore fmutex= //fmutex --> access to file;
sepaphore rdcntmutex=; // rdcntmutex --> access to reader_count
int reader_count = ; // reader_count --> the number of readers void reader(){
while ( TRUE ){
P(rdcntmutex);
if( reader_count == ) { P(fmutex); }
reader_count = reader_count + ;
V(rdcntmutex);
//Do read operation ...
P(rdcntmutex);
reader_count = reader_count - ;
if( reader_count == ) { V(fmutex); }
V(rdcntmutex);
}
}
void writer(){
while ( TRUE ){
P(fmutex);
//Do write operation ...
V(fmutex);
}
}

Writer priority solution

semaphore fmutex=, rdcntmutex=, wtcntmutex=, queue=;
int reader_count = , writer_count = ; void reader(){
while( TRUE ){
P(queue);
P(rdcntmutex);
if( reader_count == ) { P(fmutex); }
reader_count = reader_count + ;
V(rdcntmutex);
V(queue);
//Do read operation ...
P(rdcntmutex);
reader_count = reader_count - ;
if( reader_count == ) { V(fmutex); }
V(rdcntmutex);
}
}
void writer(){
while( TRUE ){
P(wtcntmutex);
if( writer_count == ) { P(queue); }
writer_count = writer_count + ;
V(wtcntmutex);
P(fmutex);
//Do write operation ...
V(fmutex);
P(wtcntmutex);
writer_count = writer_count - ;
if( writer_count == ) { V(queue); }
V(wtcntmutex);
}
}

Fair competition solution

void reader() {
// ... same as reader() in "writer priority solution" ...
} void writer(){
while( TRUE ){
P(queue);
P(fmutex);
V(queue);
//Do write operation ...
V(fmutex);
}
}

The sleeping barber problem

Presenter Notes:

  假设有一个理发店只有一个理发师,一张理发时坐的椅子,若干张普通椅子顾客供等候时坐。没有顾客时,理发师就坐在理发的椅子上睡觉。顾客一到,他不是叫醒理发师,就是离开。如果理发师没有睡觉,而在为别人理发,他就会坐下来等候。如果所有的椅子都坐满了人,最后来的顾客就会离开。 在出现竞争的情况下问题就来了,这和其它的排队问题是一样的。实际上,与哲学家就餐问题是一样的。如果没有适当的解决方案,就会导致进程之间的“饿肚子”和“死锁”。 如理发师在等一位顾客,顾客在等理发师,进而造成死锁。另外,有的顾客可能也不愿按顺序等候,会让一些在等待的顾客永远都不能理发。

代码:

#define CHAIRS 5               /* # chairs for waiting customers */
semaphore customers = ; /* # of customers waiting for service */
semaphore barbers = ; /* # of barbers waiting for customers */
semaphore mutex = ; /* for mutual exclusion */
int waiting = ; /* customers are waiting (not being cut) */ void barber(void)
{
white (TRUE) {
P(customers); /* go to sleep if # of customers is 0 */
P(mutex); /* acquire access to 'waiting' */
waiting = waiting − ; /* decrement count of waiting customers */
V(barbers); /* one barber is now ready to cut hair */
V(mutex); /* release 'waiting' */
cut_hair(); /* cut hair (outside critical region) */
}
}
void customer(void)
{
P(mutex); /* enter critical region */
if (waiting < CHAIRS) { /* if there are no free chairs, leave */
waiting = waiting + ; /* increment count of waiting customers */
V(customers); /* wake up barber if necessary */
V(mutex); /* release access to 'waiting' */
P(barbers); /* go to sleep if # of free barbers is 0 */
get_haircut(); /* be seated and be serviced */
} else {
V(mutex); /* shop is full; do not wait */
}
}

Classic IPC Problems 经典的进程间通信问题的更多相关文章

  1. 进程间通信的两种实现方式(IPC)

    进程间通信的两种实现方式(IPC) IPC: iter processing communicate 进程间通信:IPC(iter process communicate)linux free-m 可 ...

  2. 微服务的进程间通信(IPC)

    微服务的进程间通信(IPC) 目录 微服务的进程间通信(IPC) 术语 概述 通信视角 APIs 消息格式 RPC REST gRPC 断路器 API通信的健壮性 服务发现 异步消息 概念 消息 消息 ...

  3. Linux进程间通信(System V) --- 共享内存

    共享内存 IPC 原理 共享内存进程间通信机制主要用于实现进程间大量的数据传输,下图所示为进程间使用共享内存实现大量数据传输的示意图: 共享内存是在内存中单独开辟的一段内存空间,这段内存空间有自己特有 ...

  4. 网络硬盘录像机和数字硬盘录像机区别(nvr dvr ipc区别)

    DVR Digital Video Recorder 数字硬盘录像机   NVR  Network Video Recorder  网络硬盘录像机 DVR(数字硬盘录像机)和NVR(网络硬盘录像机)在 ...

  5. POSIX 进程间通信 (可移植操作系统接口)

    1.什么是POSIX标准 Portable Operating System Interface for Computing System. 他是一个针对操作系统(准确地说是针对类Unix操作系统)的 ...

  6. android IPC通信(上)-sharedUserId&amp;&amp;Messenger

    看了一本书,上面有一章解说了IPC(Inter-Process Communication,进程间通信)通信.决定结合曾经的一篇博客android 两个应用之间的通信与调用和自己的理解来好好整理总结一 ...

  7. 守护进程,互斥锁,IPC,生产者与消费者模型

    守护进程: b 进程守护 a进程,当a进程执行完毕时,b进程会跟着立马结束 守护进程用途: 如果父进程结束了,子进程无需运行了,就可以将子进程设置为父进程的守护进程 例如我们qq视频聊天时,当我们退出 ...

  8. IPC机制1

    1.Android IPC简介 Inter-Process Communication的缩写就是IPC,含义是进程间通信或是跨进程间通信,是指两个进程进行交换数据的过程. 进程是什么? 进程在pc上就 ...

  9. Linux ns 5. IPC Namespace 详解

    文章目录 1. 简介 2. 源码分析 2.1 copy_ipcs() 2.2 ipcget() 2.3 ipc_check_perms() 2.4 相关系统调用 参考文档: 1. 简介 进程间通讯的机 ...

随机推荐

  1. mysql内存数据淘汰机制和大查询会不会把内存打爆?

    首先我们说一下大查询会不会把内存打爆? 比如说主机内存有5g,但是我们一个大查询的数据有10g,这样会不会把内存打爆呢? 答案:不会 为什么? 因为mysql读取数据是采取边读边发的策略 select ...

  2. python的运算符和while循环

    一.运算符 计算机可以进行的运算有很多种,不只是加减乘除,它和我们人脑一样,也可以做很多运算. 种类:算术运算,比较运算,逻辑运算,赋值运算,成员运算,身份运算,位运算,今天我们先了解前四个. 算术运 ...

  3. ssh公私钥免密登陆

    简介ssh Secure Shell(简写SSH) 为一项建立在应用层和传输层基础上的安全协议,专门为远程登录会话和其他网络服务提供安全性的协议. SSH安全机制分为两种,一种是基于口令的安全认证,一 ...

  4. LeetCode10 Indexed tree

    Binary Indexed Tree(Fenwick tree): 是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值:经过简单修 ...

  5. Pandas处理缺失的数据

    处理丢失数据 有两种丢失数据: None np.nan(NaN) import numpy as np import pandas from pandas import DataFrame 1. No ...

  6. Numpy Ndarray对象1

    标准安装的Python中用列表(list)保存一组值,可以用来当作数组使用,不过由于列表的元素可以是任何对象,因此列表中所保存的是对象的指 针.这样为了保存一个简单的[1,2,3],需要有3个指针和三 ...

  7. Codeforces - 1194C - From S To T - 子序列 - 排序

    https://codeforces.com/contest/1194/problem/C 好像没什么好说的,要能构造s必须是t的子序列,并且相差的字符集合d是p的子集. 用双指针法求两遍子序列就可以 ...

  8. 【主机管理项目】-(models.py(一对多、多对多数据库创建代码))

    # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models class U ...

  9. shell脚本从入门到精通(中级)之提高篇

    shell 脚本入门到精通(中级) 一.shell 脚本的执行 二.输出格式化 三.数据类型 四.重定向 五.变量 一.shell 脚本的执行 1. 脚本执行的4种方法 $ ls /tmp/test. ...

  10. 关于同PC上存在多个版本的GeneXus

    如题 有的时候需要在不同的版本上开发  如我一般 有四个版本IDE 那么有的时候可能在安装的时候 提示安装失败 比如这样 这个时候你需要将安装好的GeneXus安装目录 全部备份一下 然后  从控制面 ...