当前位置: 首页 > news >正文

【操作系统】吸烟者问题

问题描述

        吸烟者问题是一个经典的同步问题,涉及三个抽烟者进程和一个供应者进程。每个抽烟者需要三种材料(烟草、纸和胶水)来卷烟,但每个抽烟者只有一种材料。供应者每次提供两种材料,拥有剩下那种材料的抽烟者可以卷烟并抽掉它。

问题分析
  1. 同步关系:供应者与三个抽烟者之间存在同步关系,供应者提供材料后,抽烟者才能开始卷烟。

  2. 互斥关系:三个抽烟者之间是互斥的,即同一时间只能有一个抽烟者卷烟。

  3. 信号量设置:需要设置信号量来控制材料的供应和抽烟者的动作。

解决方案

使用信号量来实现同步和互斥:

  • 信号量定义

    • offer1offer2offer3:分别表示供应者提供的不同组合材料(如烟草和纸、烟草和胶水、纸和胶水)。

    • finish:用于通知供应者当前抽烟者已完成抽烟。

伪代码

  • 供应者

while(1){random = 任意一个整数随机数;random = random % 3;if (random == 0)V(offer1);  // 提供烟草和纸else if (random == 1)V(offer2);  // 提供烟草和胶水elseV(offer3);  // 提供纸和胶水P(finish);  // 等待抽烟者完成
}
  • 抽烟者

while(1){P(offerX);  // 等待供应者提供材料// 拿走材料,卷烟,抽掉V(finish);  // 通知供应者已完成
}
改进
  • 由于缓冲区大小为1,四个同步信号量中至多只有一个为1,因此finish信号量用于互斥是不必要的

实现详细代码: 

1. 供应者代码(supplier.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>#define NUM_SMOKERS 3// 信号量定义
sem_t offer1;  // 提供烟草和纸
sem_t offer2;  // 提供烟草和胶水
sem_t offer3;  // 提供纸和胶水
sem_t finish;  // 通知供应者当前抽烟者已完成void* supplier(void* arg) {while (1) {// 随机选择一组材料int random = rand() % NUM_SMOKERS;if (random == 0) {printf("Supplier: Offering tobacco and paper\n");sem_post(&offer1);  // 提供烟草和纸} else if (random == 1) {printf("Supplier: Offering tobacco and matches\n");sem_post(&offer2);  // 提供烟草和胶水} else {printf("Supplier: Offering paper and matches\n");sem_post(&offer3);  // 提供纸和胶水}// 等待抽烟者完成sem_wait(&finish);}
}int main() {pthread_t supplier_thread;// 初始化信号量sem_init(&offer1, 0, 0);sem_init(&offer2, 0, 0);sem_init(&offer3, 0, 0);sem_init(&finish, 0, 0);// 创建供应者线程pthread_create(&supplier_thread, NULL, supplier, NULL);// 主线程可以继续运行其他任务或等待pthread_join(supplier_thread, NULL);// 清理信号量sem_destroy(&offer1);sem_destroy(&offer2);sem_destroy(&offer3);sem_destroy(&finish);return 0;
}
2. 抽烟者代码(smoker.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>#define NUM_SMOKERS 3// 信号量定义
extern sem_t offer1;  // 提供烟草和纸
extern sem_t offer2;  // 提供烟草和胶水
extern sem_t offer3;  // 提供纸和胶水
extern sem_t finish;  // 通知供应者当前抽烟者已完成void* smoker1(void* arg) {while (1) {sem_wait(&offer1);  // 等待供应者提供烟草和纸printf("Smoker 1: Making a cigarette with tobacco and paper\n");printf("Smoker 1: Smoking...\n");sleep(1);  // 模拟抽烟时间sem_post(&finish);  // 通知供应者已完成}
}void* smoker2(void* arg) {while (1) {sem_wait(&offer2);  // 等待供应者提供烟草和胶水printf("Smoker 2: Making a cigarette with tobacco and matches\n");printf("Smoker 2: Smoking...\n");sleep(1);  // 模拟抽烟时间sem_post(&finish);  // 通知供应者已完成}
}void* smoker3(void* arg) {while (1) {sem_wait(&offer3);  // 等待供应者提供纸和胶水printf("Smoker 3: Making a cigarette with paper and matches\n");printf("Smoker 3: Smoking...\n");sleep(1);  // 模拟抽烟时间sem_post(&finish);  // 通知供应者已完成}
}int main() {pthread_t smoker1_thread, smoker2_thread, smoker3_thread;// 初始化信号量(假设已经在supplier.c中初始化)extern sem_t offer1, offer2, offer3, finish;// 创建抽烟者线程pthread_create(&smoker1_thread, NULL, smoker1, NULL);pthread_create(&smoker2_thread, NULL, smoker2, NULL);pthread_create(&smoker3_thread, NULL, smoker3, NULL);// 主线程可以继续运行其他任务或等待pthread_join(smoker1_thread, NULL);pthread_join(smoker2_thread, NULL);pthread_join(smoker3_thread, NULL);return 0;
}

代码说明

  1. 信号量初始化

    • supplier.c中初始化信号量offer1offer2offer3finish

    • smoker.c中声明这些信号量为外部变量。

  2. 供应者逻辑

    • 供应者随机选择一组材料并提供。

    • 使用sem_post通知一个抽烟者可以开始卷烟。

    • 使用sem_wait等待抽烟者完成。

  3. 抽烟者逻辑

    • 每个抽烟者等待特定的材料组合。

    • 使用sem_wait等待供应者提供材料。

    • 模拟卷烟和抽烟过程。

    • 使用sem_post通知供应者已完成。

编译与运行

  1. 将上述代码保存为supplier.csmoker.c

  2. 使用以下命令编译代码:

    gcc -pthread -o supplier supplier.c
    gcc -pthread -o smoker smoker.c
  3. 运行程序:

    ./supplier &
    ./smoker

 

输出示例

运行程序后,你将看到类似以下的输出:

Supplier: Offering tobacco and paper
Smoker 1: Making a cigarette with tobacco and paper
Smoker 1: Smoking...
Supplier: Offering tobacco and matches
Smoker 2: Making a cigarette with tobacco and matches
Smoker 2: Smoking...
Supplier: Offering paper and matches
Smoker 3: Making a cigarette with paper and matches
Smoker 3: Smoking...

总结

        这个实现通过信号量控制供应者和抽烟者之间的同步,确保每次只有一个抽烟者能够获取材料并开始卷烟。

http://www.xdnf.cn/news/278605.html

相关文章:

  • NHANES指标推荐:LC9
  • Android第四次面试总结之Java基础篇(补充)
  • 【NTN 卫星通信】NTN关键问题的一些解决方法(一)
  • 55认知干货:深空产业
  • 2022年第十三届蓝桥杯省赛B组Java题解
  • 128. 最长连续序列
  • 【人工智能】大模型安全的深度剖析:DeepSeek漏洞分析与防护实践
  • 牛客周赛91 D题(数组4.0) 题解
  • 如何用更少的显存训练 PyTorch 模型
  • 【Java JUnit单元测试框架-60】深入理解JUnit:Java单元测试的艺术与实践
  • Spring AI 实战:第九章、Spring AI MCP之万站直通
  • HTML5实战指南:语义化标签与表单表格高级应用
  • AI日报 · 2025年5月04日|Hugging Face 启动 MCP 全球创新挑战赛
  • 《工业社会的诞生》章节
  • 相向双指针-16. 最接近的三数之和
  • 基于AWS Marketplace的快速解决方案:从选型到部署实战
  • OpenFAST 开源软件介绍
  • 大学之大:高丽大学2025.5.4
  • Java并发编程-多线程基础(三)
  • 在 Ubuntu 系统中,查看已安装程序的方法
  • Redis-----认识NoSQL
  • 网络开发基础(游戏)之 心跳机制
  • C++ 多态:原理、实现与应用
  • 科学养生,健康生活
  • Python容器与循环:数据处理的双剑合璧
  • 虚函数 vs 纯虚函数 vs 静态函数(C++)
  • 原型模式(Prototype Pattern)
  • drawDB:打造高效数据库设计流程
  • Go-Spring 全新版本 v1.1.0
  • 潮乎盲盒商城系统全开源多级分销推广海报奖品兑换试玩概率OSS云存储多端源码