操作系统实验 C++实现生产者-消费者问题

实验目的

1、进一步加深理解进程同步的概念

2、加深对进程通信的理解

3、了解Linux下共享内存的使用方法

实验内容

1、按照下面要求,写两个c程序,分别是生产者producer.c以及customer.c

2、一组生产者和一组消费者进程共享一块环形缓冲区

使用共享内存+信号量实现生产者-消费者

1、生产者进程:在第0个缓冲区写入a,第1个写入b,……,第9个写入j,并在屏幕上打印:“Producer-pid:write Y”,其中Y为写入字符,pid为生产者进程的进程ID;

2、消费者进程:依次从缓冲区中读出写入字符,读出后,将该缓冲区置为X,并在屏幕上打印:“Customer:read Y”,其中Y为读出字符,pid为消费者进程的进程ID;

基本思路

  • 定义一个数据结构:

typedef struct{         

        int write;//当前要写的缓冲区         i

        nt read;//当前要读的缓冲区         

        char buf[10];//10个缓冲区

}shared_buf;

  • 创建一个大小为sizeof(shared_buf)的共享内存
  • Producer:在buf[write]写字符‘a’+ write,然后write = (++write)% 10;
  • Customer:读buf[read]中字符,并置buf[read] = ‘X’,然后read = (++read)% 10;
  • 使用信号量:full、empty、mutex来进行同步及互斥

参考:共享内存

Linux POSIX共享内存

Linux System V共享内存

实验代码

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

// 定义共享数据结构
typedef struct {
    int write;
    int read;
    char buf[10];
} shared_buf;

// 信号量句柄
HANDLE empty_semaphore;
HANDLE full_semaphore;
HANDLE mutex_semaphore;

// 共享内存句柄
HANDLE shared_memory_handle;
shared_buf* shared_memory_ptr;

// 生产者函数
unsigned __stdcall producer(void* arg) {
    int pid = _getpid();
    for (int i = 0; i < 20; i++) {
        // 等待有空缓冲区
        WaitForSingleObject(empty_semaphore, INFINITE);
        // 互斥访问共享内存
        WaitForSingleObject(mutex_semaphore, INFINITE);

        char ch = 'a' + i;
        shared_memory_ptr->buf[shared_memory_ptr->write] = ch;
        printf("Producer - %d: write %c\n", pid, ch);
        shared_memory_ptr->write = (shared_memory_ptr->write + 1) % 10;

        ReleaseSemaphore(mutex_semaphore, 1, NULL);
        ReleaseSemaphore(full_semaphore, 1, NULL);
    }
    return 0;
}

// 消费者函数
unsigned __stdcall consumer(void* arg) {
    int pid = _getpid();
    for (int i = 0; i < 20; i++) {
        // 等待有满缓冲区
        WaitForSingleObject(full_semaphore, INFINITE);
        // 互斥访问共享内存
        WaitForSingleObject(mutex_semaphore, INFINITE);

        char ch = shared_memory_ptr->buf[shared_memory_ptr->read];
        shared_memory_ptr->buf[shared_memory_ptr->read] = 'X';
        printf("Consumer - %d: read %c\n", pid, ch);
        shared_memory_ptr->read = (shared_memory_ptr->read + 1) % 10;

        ReleaseSemaphore(mutex_semaphore, 1, NULL);
        ReleaseSemaphore(empty_semaphore, 1, NULL);
    }
    return 0;
}

int main() {
    // 创建信号量
    empty_semaphore = CreateSemaphore(NULL, 10, 10, NULL);
    full_semaphore = CreateSemaphore(NULL, 0, 10, NULL);
    mutex_semaphore = CreateSemaphore(NULL, 1, 1, NULL);

    // 创建共享内存
    shared_memory_handle = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0,
        sizeof(shared_buf),
        "SharedMemory"
    );
    if (shared_memory_handle == NULL) {
        perror("CreateFileMapping");
        return 1;
    }
    shared_memory_ptr = (shared_buf*)MapViewOfFile(
        shared_memory_handle,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        sizeof(shared_buf)
    );
    if (shared_memory_ptr == NULL) {
        perror("MapViewOfFile");
        CloseHandle(shared_memory_handle);
        return 1;
    }

    // 初始化共享内存
    shared_memory_ptr->write = 0;
    shared_memory_ptr->read = 0;
    for (int i = 0; i < 20; i++) {
        shared_memory_ptr->buf[i] = 'X';
    }

    // 创建生产者和消费者线程
    unsigned thread_id_producer;
    unsigned thread_id_consumer;
    HANDLE producer_thread = (HANDLE)_beginthreadex(NULL, 0, producer, NULL, 0, &thread_id_producer);
    HANDLE consumer_thread = (HANDLE)_beginthreadex(NULL, 0, consumer, NULL, 0, &thread_id_consumer);

    // 等待线程结束
    WaitForSingleObject(producer_thread, INFINITE);
    WaitForSingleObject(consumer_thread, INFINITE);

    // 清理资源
    UnmapViewOfFile(shared_memory_ptr);
    CloseHandle(shared_memory_handle);
    CloseHandle(empty_semaphore);
    CloseHandle(full_semaphore);
    CloseHandle(mutex_semaphore);
    CloseHandle(producer_thread);
    CloseHandle(consumer_thread);

    return 0;
}

实验结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/918621.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Easyexcel(1-注解使用)

文章链接&#xff1a; Easyexcel&#xff08;1-注解使用&#xff09; 版本依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.3</version> </dependency>ExcelProperty 指定…

最新版xAI LLM 模型Grok-2 上线

xAI&#xff01;Grok-2 最新版开启公测&#xff01;”。这是我注册成功的截图&#xff0c;使用国内的邮箱就可以注册使用了&#xff01; Grok API公测与免费体验: Grok API开启公测&#xff0c;提供免费体验128k上下文支持&#xff0c;。Grok-Beta与马斯克: 马斯克庆祝特朗普当…

css数据不固定情况下,循环加不同背景颜色

<template><div><p v-for"(item, index) in items" :key"index" :class"getBackgroundClass(index)">{{ item }}</p></div> </template><script> export default {data() {return {items: [学不会1, …

MySQL的聚簇索引和二级索引

索引按照物理实现方式&#xff0c;索引可以分为 2 种&#xff1a;聚簇&#xff08;聚集&#xff09;和非聚簇&#xff08;非聚集&#xff09;索引。也可以把非聚集索引称为二级索引或者辅助索引。 一.聚簇索引 聚簇索引并不是一种单独的索引类型&#xff0c;而是一种数据存储方…

【Pytorch】torch.nn.functional模块中的非线性激活函数

在使用torch.nn.functional模块时&#xff0c;需要导入包&#xff1a; from torch.nn import functional 以下是常见激活函数的介绍以及对应的代码示例&#xff1a; tanh (双曲正切) 输出范围&#xff1a;(-1, 1) 特点&#xff1a;中心对称&#xff0c;适合处理归一化后的数据…

神经网络11-TFT模型的简单示例

Temporal Fusion Transformer (TFT) 是一种用于时间序列预测的深度学习模型&#xff0c;它结合了Transformer架构的优点和专门为时间序列设计的一些优化技术。TFT尤其擅长处理多变量时间序列数据&#xff0c;并且能够捕捉到长期依赖关系&#xff0c;同时通过自注意力机制有效地…

学习threejs,使用TWEEN插件实现动画

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.PLYLoader PLY模型加…

世界坐标系、相机坐标系、图像物理坐标系、像素平面坐标系

坐标系及其转换在计算机视觉领域占据核心地位。理解如何从一个坐标系转换到另一个坐标系&#xff0c;不仅是理论上的需要&#xff0c;也是实际应用中不可或缺的技能。 一、世界坐标系的定义 世界坐标系是一个全局的坐标系统&#xff0c;用于定义场景中物体的位置。在这个坐标…

03-axios常用的请求方法、axios错误处理

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

Redis/Codis性能瓶颈揭秘:网卡软中断的影响与优化

目录 现象回顾 问题剖析 现场分析 解决方案 总结与反思 1.调整中断亲和性&#xff08;IRQ Affinity&#xff09;&#xff1a; 2.RPS&#xff08;Receive Packet Steering&#xff09;和 RFS&#xff08;Receive Flow Steering&#xff09;&#xff1a; 近期&#xff0c;…

openwebui使用

文章目录 1、feature2、安装使用2.1 安装过程2.2 安装好后 1、feature 可以加载多个大模型 同时回复 模型问答: 使用vLLM框架部署模型&#xff0c;再使用Open WebUI直接进行模型问答 多模型支持: 多模型回复比对&#xff08;Qwen2-72B-Instruct, llama3-70b-8192, mixtral-8x7…

汽车资讯新引擎:Spring Boot技术领航

3系统分析 3.1可行性分析 通过对本汽车资讯网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本汽车资讯网站采用SSM框架&#xff0c;JAVA作为开发语言&#…

应用系统开发(12) Zync中实现数字相敏检波

在 Xilinx Zynq 系列(如 Zynq-7000 或 Zynq UltraScale+)中实现数字相敏检波(DSP,Digital Synchronous Detection)可以通过硬件(PL部分,FPGA逻辑)和软件(PS部分,ARM Cortex-A 处理器)的协同工作来实现。以下是一个详细的设计方法,包括基本原理和 Zynq 的实现步骤。…

《译文》2024年11月数维杯国际大学生数学建模挑战赛题目

# 赛题正式发布 2024年第十届数维杯国际大学生数学建模挑战赛顺利开赛&#xff0c;竞赛开始时间为北京时间2024年11月15日09:00至北京时间2024年11月19日09:00&#xff0c;共计4天&#xff0c;竞赛题目正式发布&#xff0c;快来一起围观&#xff0c;你认为今年的哪个题目更具有…

apk反编译修改教程系列-----apk应用反编译中AndroidManifest.xml详细代码释义解析 包含各种权限 代码含义【二】

💝💝💝💝在上期博文中解析了一个常规apk中 AndroidManifest.xml的权限以及代码。应粉丝需求。这次解析一个权限较高的apk。这款apk是一个家长管控的应用。需求的各种权限较高。而且通过管控端可以设置控制端的app隐藏与否。 通过博文了解💝💝💝💝 1💝💝…

【UGUI】背包的交互01(道具信息跟随鼠标+道具信息面板显示)

详细程序逻辑过程 初始化物品栏&#xff1a; 在 Awake 方法中&#xff0c;通过标签找到提示框和信息面板。 循环生成10个背包格子&#xff0c;并为每个格子设置图标和名称。 为每个格子添加 UInterMaager232 脚本&#xff0c;以便处理交互事件。 关闭提示框和信息面板&#…

Docker: ubuntu系统下Docker的安装

安装依赖 操作系统版本 Ubuntu Kinetic 22.10Ubuntu Jammy 24.04 (LTS)Ubuntu Jammy 22.04 (LTS)Ubuntu Focal 20.04 (LTS)Ubuntu Bionic 18.04 (LTS) CPU架构支持 ARMx86_64 查看我们的系统版本信息 uname -a通过该命令查得cpu架构是x86_64的&#xff1b; cat /etc/*re…

Nacos 配置中心变更利器:自定义标签灰度

作者&#xff1a;柳遵飞 配置中心被广泛使用 配置中心是 Nacos 的核心功能之一&#xff0c;接入配置中心&#xff0c;可以实现不重启线上应用的情况下动态改变程序的运行期行为&#xff0c;在整个软件生命周期中&#xff0c;可以极大降低了软件构建及部署的成本&#xff0c;提…

基于RK3568J多网口电力可信物联网关解决方案

前言 随着工业物联网的普及和功能越来越强大&#xff0c;边缘计算网关应运而生。 边缘计算有效降低了云端服务器的负载、大大降低了带宽的占用&#xff0c;同时也为本地化的区域自治提供了便利条件。 边缘计算网关&#xff0c;完美地发挥了“边”与“端” 结合优势&#xff0c…

无人机飞手入门指南

无人机飞手入门指南旨在为初学者提供一份全面的学习路径和实践建议&#xff0c;帮助新手快速掌握无人机飞行技能并了解相关法规知识。以下是一份详细的入门指南&#xff1a; 一、了解无人机基础知识 1. 无人机构造&#xff1a;了解无人机的组成部分&#xff0c;如机身、螺旋桨…