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. hdu6570Wave (暴力求解)

    Problem Description Avin is studying series. A series is called "wave" if the following co ...

  2. from、includes、indexOf

    from.includes.indexOf:https://blog.csdn.net/j59580/article/details/53897630?utm_source=blogxgwz1 语法 ...

  3. 洛谷 P1972 [SDOI2009]HH的项链(树状数组,离线)

    传送门 解题思路 因为是求区间的不同种类数,所以我们用树状数组(貌似并没有什么直接联系) (...表示到) 还是和原来一样,用s[i]来表示a[i-lowbit(i)]...a[i]的种类数. 因为有 ...

  4. go 学习之fmt包

    基本模式fmt 方法可以大致分为 print, scan两类, 根据基础方法可以构建特定方法. Print 将参数写入字符串或io.writer scan 从字符串或 io.Reader 读取指定数据 ...

  5. Xshell实现Windows和使用跳板机跳转的远程Linux互传文件

    适用于Linux CentOS版本,本地电脑是Win10版本 查询Linux版本: $lsb_release -a $cat /etc/issue 1.使用Xshell 连接上服务器 2.安装文件传输 ...

  6. 关于自带的sql developer修改java.exe版本的解决办法

    第一次安装oracle11gR2后,就很好奇的点了一下,当点击应用程序开发下的sql developer后,就弹出一个窗口,要选择一个java.exe的路径,我就讲本机中的JDK1.7下的java.e ...

  7. Pull Request的正确打开方式(如何在GitHub上贡献开源项目)

    Pull Request的正确打开方式(如何在GitHub上贡献开源项目) GitHub的官方帮助如下: Fork A Repo: https://help.github.com/articles/f ...

  8. springcloud费话之Eureka服务访问(restTemplate)

    目录: springcloud费话之Eureka基础 springcloud费话之Eureka集群 springcloud费话之Eureka服务访问(restTemplate) springcloud ...

  9. 【新手向】一个超简单的jquery.mCustomScrollbar滚动条插件Demo

    <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script> < ...

  10. JavaScript给动态插入的元素添加事件绑定

    由于实际的需要,有时需要往网页中动态的插入HTML内容,并在插入的节点中绑定事件处理函数.我们知道,用Javascript向HTML文档中 插入内容,有两种方法, 一种是在写HTML代码写入JS,然后 ...