经典进程同步问题——吸烟者问题

吸烟者问题是为了解决“可以生产多个产品的单生产者”问题提供了一个思路。

问题描述:有三个抽烟者和一个供应者。每个抽烟者不停地卷烟抽,组成一根烟需要三种材料:烟草、纸和胶水。三个抽烟者中,第一个有烟草,第二个有纸,第三个拥有胶水。供应者无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉已完成,那么供应者可以继续提供另外两种材料,如此重复(让三个抽烟者轮流地抽烟)。

问题分析

  1. 关系分析。供应者与三个抽烟者分别是同步关系。供应着无法同时满足两个或两个以上的抽烟者,所以三个抽烟者是互斥关系。
  2. 整理思路。这里有四个进程,一个供应者,三个抽烟者。
  3. 信号量设置。信号量offer1,offer2,offer3分别表示烟草和纸的组合、烟草和胶水的组合、纸和胶水的组合。信号量finish用于互斥进行抽烟动作。

代码描述如下:

  1. int i=0;  
  2. semaphore offer1=0;//定义信号量对应烟草和纸的组合  
  3. semaphore offer2=0;//定义信号量对应烟草和胶水的组合  
  4. semaphore offer3=0;//定义信号量对应纸和胶水的组合  
  5. semaphore finish=0;//定义信号量表示抽烟是否完成  
  6. process P1(){  
  7.   if(i==0)  
  8.     V(offer1); //提供烟草和纸  
  9.   else if(i==1)  
  10.     V(offer2);//提供烟草和胶水  
  11.   else if(i==2)  
  12.     V(offer3);//提供纸和胶水  
  13.   任意两种材料放在桌子上;  
  14.   P(finish);  
  15.   i=(i+1)%3;
  16. }  
  17. process P2(){//拥有烟草者  
  18.   while(1){  
  19.    P(offer3);  
  20.    拿纸和胶水,卷成烟,抽掉  
  21.    V(finish);  
  22.   }  
  23. }  
  24. process P3(){//拥有纸者  
  25.   while(1){  
  26.    P(offer2);  
  27.    拿烟草和胶水,卷成烟,抽掉  
  28.    V(finish);  
  29.   }  
  30. }  
  31. process P4(){//拥有胶水者  
  32.   while(1){  
  33.    P(offer1);  
  34.    拿烟草和纸,卷成烟,抽掉  
  35.    V(finish);  
  36.   }  
  37. }  

其实吸烟者问题还是比较好理解的,不过要确认的是这里供应者一次是供应两种,那么就把它看成一种组合就行。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
吸烟者问题是一个经典进程同步问题,其中有三个进程,分别代表烟草商、吸烟者和抽烟者。烟草商提供烟草和纸,吸烟者需要烟草和纸才能卷烟,而抽烟者需要烟草和火柴才能抽烟。这三个进程分别需要互相合作才能完成任务。 下面是一个使用信号量实现的解决方案: ```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() 函数通知等待的吸烟者进程。 这样,就实现了一个简单的吸烟者问题解决方案。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值