【C/C++解决读者-写者问题】

news2024/12/23 23:03:58

目录

  • 一、问题描述
  • 二、问题分析
  • 三、三种策略实现
      • 1.读者优先策略
      • 2. 读写公平策略
      • 3.写者优先策略(后续更新)

一、问题描述

有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程(只是读数据,不会对数据产生影响,而消费者读数据时,会将数据取走,因此不能两个消费者一起读数据)同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。
因此要求:

  1. 允许多个读者可以同时对文件执行读操作;
  2. 只允许一个写者往文件中写信息;
  3. 任一写者在完成写操作之前不允许其他读者或写者工作;
  4. 写者执行写操作前,应让已有的读者和写者全部退出。

二、问题分析

  • 首先,分析问题中的同步互斥关系。读者和写者是互斥关系、写者和写者是互斥关系,而读者和读者不存在互斥关系。
  • 其次,考虑读写进程并发运行的情况。若读者和写者并发地读数据或者写数据,我们应该优先处理读者进程,还是写者进程亦或是读写公平。
  • 最后,设计信号量来控制互斥关系,以及读者、写者之间的优先执行策略。

三、三种策略实现

/*  本项目仅用于模拟解决读者-写者问题。
    1.包含若干读者线程和写者线程用于模拟读者进程和写者进程。
    2.包含一个单个资源临界缓冲区用于存放和读取数据。
    3.分别实现读者优先、写者优先以及读写公平三种策略。
*/

1.读者优先策略

在这里插入图片描述
ReadHighPriority.cpp

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#define NUM_READERS 3   //读者进程数量
#define NUM_WRITERS 2   //写者进程数量

static int data = 0;   //初始化临界缓存区为空
static int readers_count = 0;  //记录读者进程数量
static HANDLE mutex;   //用于实现读者进程对于readers_count变量的互斥访问
static HANDLE rw_semaphore;    //用于实现读者和写者互斥访问临界缓冲区

static DWORD WINAPI Reader(LPVOID lpParam) {
    int reader_id = *(int*)lpParam;

    while (1) {
        WaitForSingleObject(mutex, INFINITE);
        readers_count++;
        if (readers_count == 1) {
            WaitForSingleObject(rw_semaphore, INFINITE);
        }
        ReleaseMutex(mutex);

        printf("Reader %d is reading data: %d\n", reader_id, data);
        Sleep(1000);  // 模拟读取数据的耗时

        WaitForSingleObject(mutex, INFINITE);
        readers_count--;
        if (readers_count == 0) {
            ReleaseSemaphore(rw_semaphore, 1, NULL);
        }
        ReleaseMutex(mutex);

        Sleep(2000);  // 读者休息一段时间后再次读取数据
    }

    return 0;
}

DWORD WINAPI Writer(LPVOID lpParam) {
    int writer_id = *(int*)lpParam;

    while (1) {
        WaitForSingleObject(rw_semaphore, INFINITE);

        data++;  // 写入数据
        printf("Writer %d is writing data: %d\n", writer_id, data);
        Sleep(2000);  // 模拟写入数据的耗时

        ReleaseSemaphore(rw_semaphore, 1, NULL);

        Sleep(3000);  // 写者休息一段时间后再次写入数据
    }

    return 0;
}

int main() {
    // 创建互斥锁和读写信号量
    mutex = CreateMutex(NULL, FALSE, NULL);
    rw_semaphore = CreateSemaphore(NULL, 1, 1, NULL);

    // 创建读者线程
    HANDLE reader_threads[NUM_READERS];
    int reader_ids[NUM_READERS];
    for (int i = 0; i < NUM_READERS; i++) {
        reader_ids[i] = i + 1;
        reader_threads[i] = CreateThread(NULL, 0, Reader, &reader_ids[i], 0, NULL);
    }

    // 创建写者线程
    HANDLE writer_threads[NUM_WRITERS];
    int writer_ids[NUM_WRITERS];
    for (int i = 0; i < NUM_WRITERS; i++) {
        writer_ids[i] = i + 1;
        writer_threads[i] = CreateThread(NULL, 0, Writer, &writer_ids[i], 0, NULL);
    }

    // 等待所有读者线程和写者线程结束
    WaitForMultipleObjects(NUM_READERS, reader_threads, TRUE, INFINITE);
    WaitForMultipleObjects(NUM_WRITERS, writer_threads, TRUE, INFINITE);

    // 关闭句柄
    CloseHandle(mutex);
    CloseHandle(rw_semaphore);

    return 0;
}

2. 读写公平策略

在这里插入图片描述

ReadrWriterEqualPriority.cpp

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#define NUM_READERS 3   //读者进程数量
#define NUM_WRITERS 2   //写者进程数量

static int data = 0;   //初始化临界缓存区为空
static int readers_count = 0;  //记录读者进程数量
static HANDLE mutex;   //用于实现读者进程对于readers_count变量的互斥访问
static HANDLE rw_semaphore;    //用于实现读者和写者互斥访问临界缓冲区
static HANDLE w_priority;   //用于实现写优先

static DWORD WINAPI Reader(LPVOID lpParam) {
    int reader_id = *(int*)lpParam;

    while (1) {
        WaitForSingleObject(w_priority, INFINITE);
        WaitForSingleObject(mutex, INFINITE);
        readers_count++;
        if (readers_count == 1) {
            WaitForSingleObject(rw_semaphore, INFINITE);
        }
        ReleaseMutex(mutex);
        ReleaseSemaphore(w_priority, 1, NULL);

        printf("Reader %d is reading data: %d\n", reader_id, data);
        Sleep(1000);  // 模拟读取数据的耗时

        WaitForSingleObject(mutex, INFINITE);
        readers_count--;
        if (readers_count == 0) {
            ReleaseSemaphore(rw_semaphore, 1, NULL);
        }
        ReleaseMutex(mutex);

        Sleep(2000);  // 读者休息一段时间后再次读取数据
    }

    return 0;
}

DWORD WINAPI Writer(LPVOID lpParam) {
    int writer_id = *(int*)lpParam;

    while (1) {
        WaitForSingleObject(w_priority, INFINITE);
        WaitForSingleObject(rw_semaphore, INFINITE);

        data++;  // 写入数据
        printf("Writer %d is writing data: %d\n", writer_id, data);
        Sleep(2000);  // 模拟写入数据的耗时

        ReleaseSemaphore(rw_semaphore, 1, NULL);
        ReleaseSemaphore(w_priority, 1, NULL);

        Sleep(3000);  // 写者休息一段时间后再次写入数据
    }

    return 0;
}

int main() {
    // 创建互斥锁和读写信号量
    mutex = CreateMutex(NULL, FALSE, NULL);
    rw_semaphore = CreateSemaphore(NULL, 1, 1, NULL);
    w_priority = CreateSemaphore(NULL,1,1,NULL);

    // 创建读者线程
    HANDLE reader_threads[NUM_READERS];
    int reader_ids[NUM_READERS];
    for (int i = 0; i < NUM_READERS; i++) {
        reader_ids[i] = i + 1;
        reader_threads[i] = CreateThread(NULL, 0, Reader, &reader_ids[i], 0, NULL);
    }

    // 创建写者线程
    HANDLE writer_threads[NUM_WRITERS];
    int writer_ids[NUM_WRITERS];
    for (int i = 0; i < NUM_WRITERS; i++) {
        writer_ids[i] = i + 1;
        writer_threads[i] = CreateThread(NULL, 0, Writer, &writer_ids[i], 0, NULL);
    }

    // 等待所有读者线程和写者线程结束
    WaitForMultipleObjects(NUM_READERS, reader_threads, TRUE, INFINITE);
    WaitForMultipleObjects(NUM_WRITERS, writer_threads, TRUE, INFINITE);

    // 关闭句柄
    CloseHandle(mutex);
    CloseHandle(rw_semaphore);
    CloseHandle(w_priority);
    return 0;
}

3.写者优先策略(后续更新)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

将数据转化为创新机会:8 种业务分析模型指南

当我们想要创新时&#xff0c;往往需要有实际的依据来支撑我们的想法。商业咨询顾问通常被认为是聪明的人&#xff0c;他们拥有模型化的分析思维&#xff0c;这种思维方式可以帮助他们更好地理解市场、竞争对手和客户需求。商业分析思维是一种系统性的思考方式&#xff0c;它可…

力扣 222. 完全二叉树的节点个数

题目来源&#xff1a;https://leetcode.cn/problems/count-complete-tree-nodes/description/ C题解1&#xff1a;层序遍历计算节点。 时间复杂度&#xff1a;O(n)空间复杂度&#xff1a;O(n) /*** Definition for a binary tree node.* struct TreeNode {* int val;* …

已开源!网易云信的热点探测平台实践

背景 对于一个互联网平台&#xff0c;特别是 toB 的 PaaS/SaaS 平台&#xff0c;热点 key 是一个绕不过去的问题。作为一个开放的系统&#xff0c;平台每天要承载来自大量的外部系统或者海量终端的请求&#xff0c;虽然所有的请求都需要满足开放平台定义好的鉴权规则&#xff0…

虚幻引擎(UE5)-大世界分区WorldPartition教程(四)

文章目录 前言一、Data Layers的使用1.添加Actor到Data Layers2.运行时处理 总结 上一篇&#xff1a;虚幻引擎(UE5)-大世界分区WorldPartition教程(三) 前言 Data Layers&#xff08;UE4中叫Layers&#xff09;用于将Actor划分到不同的Layer中&#xff0c;通过在编辑器和运行…

Qt在Ubuntu下如何进行桌面软件开发?

文章目录 0.引言1.新建项目2.编写第一个程序3.在Qt外部启动程序 0.引言 笔者研究的方向涉及在ubuntu中运行代码&#xff0c;早先是直接利用控制台运行代码文件&#xff0c;在控制台中虽然设法将代码精简到一个三个文件中&#xff0c;只需要在控制台运行这三个文件即可&#xff…

应用在5W~20W无线充电器中的电机驱动芯片

随着用电设备对供电质量、安全性、可靠性、方便性、即时性、特殊场合、特殊地理环境等要求的不断提高&#xff0c;使得接触式电能传输方式越来越不能满足实际需要。无线充电器是利用电磁感应原理进行充电的设备&#xff0c;其原理和变压器相似&#xff0c;通过在发送和接收端各…

基于深度学习的高精度条形码二维码检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度条形码二维码检测识别系统可用于日常生活中或野外来检测与定位条形码二维码目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的条形码二维码目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系…

2023上半年软考系统分析师科目一整理-07

2023上半年软考系统分析师科目一整理-07 信息资源规划&#xff08;Information Resource Planning&#xff0c;IRP&#xff09;是信息化建设的基础工程&#xff0c;IRP强调将需求分析与&#xff08; &#xff09;结合起来。IRP的过程大致可以分为7个步骤&#xff0c;其中&#…

微信小程序组件间通讯

1.父传子 1.1父组件 1.1.1wxml文件 <!-- 定义的my-props组件 --> <my-props count"{{count}}"></my-props> <!-- 分割线 --> <view></view> <view>父组件的count值:{{count}}</view> <button bindtap"ad…

一步一步学OAK之五:通过OAK相机实现边缘检测

目录 边缘检测简介Setup 1: 创建文件Setup 2: 安装依赖Setup 3: 导入需要的包Setup 4: 创建pipelineSetup 5: 创建节点创建相机节点创建边缘检测节点创建XLinkOut数据交互的节点 Setup 6:设置相关属性设置彩色相机的相关属性设置左侧和右侧的单目相机的相关属性设置边缘检测器的…

【计算机网络 - 第三章】运输层

目录 一、多路复用和多路分解 1、运输层端口号 2、概述 3、原理 1、无连接的多路复用与多路分解 - UDP 2、面向连接的多路复用与多路分解 - TCP 二、无连接运输——UDP用户数据报协议 1、UDP概述 2、UDP的优点 三、可靠数据传输原理 1、概述 2、rdt1.0——可靠信道上…

【AUTOSAR】BMS开发实际项目讲解(十一)----电池管理系统相关项功能安全要求

相关项功能安全要求 SG-BMS-1 : BMS系统应防止电池单体过充导致热失控&#xff08;ASIL C&#xff09; 功能框图&#xff08;SG-BMS-1&#xff09; 功能组件说明 功能组件ID 功能组件名称 描述 ASIL等级 FSC-FC-01 Detection Cell Volt&Temp 采集表征单体电压和温度的…

Qt中QCompleter自动补全功能

在Qt中有QCompleter这个类可以和QLineEdit组合实现自动补全功能&#xff0c;类似搜索框形式的&#xff0c; 1.QCompleter类可以在输入框输入字符时&#xff0c;进行提示可以匹配上的字符 例&#xff1a;为QLineEdit设置自动补全QLineEdit* pLineEdit new QLineEdit(this);QStr…

【算法】最长递增子序列:动态规划贪心+二分查找

文章目录 最长递增子序列解法一&#xff1a;动态规划解法二&#xff1a;LIS 和 LCS 的关系解法三&#xff1a;贪心 二分查找 相关题目673. 最长递增子序列的个数 https://leetcode.cn/problems/number-of-longest-increasing-subsequence/1964. 找出到每个位置为止最长的有效障…

29.组件库 Element UI

Element UI是PC端常用的组件库&#xff0c;支持vue2与vue3&#xff0c;vue2项目使用的叫 Element UI,vue3使用的叫 Elements Plus&#xff0c;官网地址 一个 Vue 3 UI 框架 | Element Plus 我们下面的代码都是以vue3为例 目录 1 安装 2 引入 3 使用 1 安装 2 引入 完…

快消EDI:联合利华Unilever EDI需求分析

联合利华&#xff08;Unilever&#xff09;是一家跨国消费品公司&#xff0c;总部位于英国和荷兰&#xff0c;在全球范围内经营着众多知名品牌&#xff0c;涵盖了食品、饮料、清洁剂、个人护理产品等多个领域。作为一家跨国公司&#xff0c;联合利华在全球各地都有业务和生产基…

el-table表单一键展开折叠,展开部分后一键全部展开或折叠

实现功能&#xff1a; 1.表单一键展开或者一键折叠 2.表单点击展开一部分后&#xff0c;再次点击展开或折叠按钮可以全部展开或全部折叠 3.完整代码在最后 1.建立el-table的树形结构 1.ref"table"&#xff0c;用节点绑定的方式实现 2.data&#xff1a;树形结构…

Redis系列--数据过期清除策略缓存淘汰策略

一、过期策略 一、前言 Redis 所有的数据结构都可以设置过期时间&#xff0c;时间一到&#xff0c;就会自动删除。可以想象里面有一个专门删除过期数据的线程&#xff0c;数据已过期就立马删除。这个时候可以思考一下&#xff0c;会不会因为同一时间太多的 key 过期&#xff0…

windows电脑设置每天自动关机

有时候我们需要我们的笔记本或者电脑在每天固定的时间自动关机&#xff0c;但是windows本身是没有带这个设置的&#xff0c;下面记录下如何设置电脑每天自动关机&#xff0c;无需安装任何第三方软件&#xff1b; 文章目录 一、设置自动关机程序二、取消自动关机三、Windows任务…

chatgpt赋能python:Python连接表

Python连接表 Python作为一种高级编程语言&#xff0c;可以用于各种各样的任务。其中之一就是连接表格数据。连接表是在数据管理中非常重要的概念&#xff0c;因为它可以将不同表格中的数据合并在一起&#xff0c;从而使我们能够更好地分析和理解数据。在这篇文章中&#xff0…