吸烟者问题——进程同步

一、问题描述:

某系统有三个吸烟者进程和一个经销商进程:

  • 每个吸烟者连续不断做烟卷并抽他做好的烟卷,做一支烟卷需要烟草、纸、火柴三种原料,这3个吸烟者分别掌握有烟草、纸和火柴;
  • 经销商源源不断地提供上述三种原料,但他只将其中的两种原料放在桌上,具有另一种原料的吸烟者就可做烟卷并抽烟,且在做完后给经销商发信号,然后经销商再拿出两种原料放在桌上,如此反复。
  • 试设计一个同步算法来描述他们的活动。

二、问题分析

吸烟者问题是经典的进程同步问题,其特点在于信号量的设置,本题的关键问题是判断有几个临界资源。烟草、纸和火柴三种原料并不能简单地看成是三种临界资源,因为它们并不是以单独的形式被三个吸烟者进程所竞争,而是以固定的组合被三个进程所申请因此可以考虑如下设置:

  • 三个信号量t1、t2和t3分别代表三种原料组合,即t1表示烟草和纸的组合信号量,t2表示烟草和火柴的组合信号量,t3表示纸和火柴的组合信号量,初值均为0。
  • 经销商一次只能提供一种组合,可以看作是放一个产品的缓冲区,资源量为一个组合,于是我们设置缓冲区的资源信号量为s,初值为1。由于该资源量为1,故可以同时作为互斥量来使用,可以省略对缓冲区操作的互斥信号量。

本题还有一个特点就是经销商在提供原料时是随机的,预先并不知道经销商会放什么原料,只有在提供以后才知道,所以在对信号量操作时必须预先搞清楚到底是放了什么原料的组合,再对相应的信号量操作。这个过程在经销商进程中有所体现。

因此简化分析:

1)三个吸烟者和一个经销商,三个吸烟者各自拥有的材料不同,可以吸烟的条件不一样,具体看经销商往桌子上放的原料

2)每个吸烟者都需要一个进程(为烟草拥有者进程、纸拥有者进程、火柴拥有者进程)分别和经销商进程进行同步

3)互斥资源:桌子;

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
吸烟者问题一个经典进程同步问题,其中有三个进程,分别代表烟草商、吸烟者和抽烟者。烟草商提供烟草和纸,吸烟者需要烟草和纸才能卷烟,而抽烟者需要烟草和火柴才能抽烟。这三个进程分别需要互相合作才能完成任务。 下面是一个使用信号量实现的解决方案: ```C++ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <semaphore.h> #include <pthread.h> #define N 3 // 吸烟者的数量 sem_t tobacco; // 烟草信号量 sem_t paper; // 纸信号量 sem_t match; // 火柴信号量 sem_t agent; // 烟草商信号量 void *smoker(void *arg) { int id = *(int *)arg; while (1) { switch (id) { case 0: // 吸烟者 A sem_wait(&tobacco); sem_wait(&paper); printf("Smoker A is smoking...\n"); sleep(1); sem_post(&agent); break; case 1: // 吸烟者 B sem_wait(&tobacco); sem_wait(&match); printf("Smoker B is smoking...\n"); sleep(1); sem_post(&agent); break; case 2: // 吸烟者 C sem_wait(&paper); sem_wait(&match); printf("Smoker C is smoking...\n"); sleep(1); sem_post(&agent); break; default: break; } } return NULL; } void *agent_thread(void *arg) { while (1) { sem_wait(&agent); int r = rand() % 3; switch (r) { case 0: // 提供烟草和纸 printf("Agent provides tobacco and paper.\n"); sem_post(&tobacco); sem_post(&paper); break; case 1: // 提供烟草和火柴 printf("Agent provides tobacco and match.\n"); sem_post(&tobacco); sem_post(&match); break; case 2: // 提供纸和火柴 printf("Agent provides paper and match.\n"); sem_post(&paper); sem_post(&match); break; default: break; } } return NULL; } int main(int argc, char *argv[]) { pthread_t tid[N + 1]; int ids[N]; sem_init(&tobacco, 0, 0); sem_init(&paper, 0, 0); sem_init(&match, 0, 0); sem_init(&agent, 0, 1); pthread_create(&tid[0], NULL, agent_thread, NULL); for (int i = 0; i < N; i++) { ids[i] = i; pthread_create(&tid[i + 1], NULL, smoker, &ids[i]); } for (int i = 0; i <= N; i++) { pthread_join(tid[i], NULL); } sem_destroy(&tobacco); sem_destroy(&paper); sem_destroy(&match); sem_destroy(&agent); return 0; } ``` 在这个实现中,使用了四个信号量:烟草信号量、纸信号量、火柴信号量和烟草商信号量。烟草商信号量的初始值为 1,表示烟草商一开始就可以提供烟草和纸或者烟草和火柴。吸烟者进程在等待烟草、纸和火柴的过程中都使用了 sem_wait() 函数,当某个条件被满足时,使用 sem_post() 函数通知烟草商提供相应的物品。 在烟草商进程中使用了一个无限循环,不断地提供烟草和纸、烟草和火柴或者纸和火柴中的一种,每次提供完毕后使用 sem_post() 函数通知等待的吸烟者进程。 这样,就实现了一个简单的吸烟者问题解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值