C语言实现 操作系统 经典的进程同步问题(3)

news2024/10/3 7:16:48

读者-写者问题

1、利用记录型信号量解决读者-写者问题

通过POSIX信号量实现。

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
#include <semaphore.h>  
#include <unistd.h>  
  
#define NUM_READERS 5  
#define NUM_WRITERS 3  
#define READ_TIME 2  
#define WRITE_TIME 1  
  
sem_t rw_mutex;      // 保护共享资源的互斥锁  
sem_t mutex;         // 保护读者计数的互斥锁  
int read_count = 0;  // 当前正在读取的读者数量  
  
void *reader(void *arg) {  
    int reader_id = *((int *)arg);  
    while (1) {  
        // 请求读取锁  
        sem_wait(&mutex);  
        read_count++;  
        if (read_count == 1) {  
            sem_wait(&rw_mutex);  // 第一个读者获得写锁(独占)  
        }  
        sem_post(&mutex);  
  
        // 读取操作  
        printf("Reader %d is reading.\n", reader_id);  
        sleep(READ_TIME);  
  
        // 释放读取锁  
        sem_wait(&mutex);  
        read_count--;  
        if (read_count == 0) {  
            sem_post(&rw_mutex);  // 最后一个读者释放写锁  
        }  
        sem_post(&mutex);  
  
        sleep(1);  // 读者休息一会儿再尝试读取  
    }  
    return NULL;  
}  
  
void *writer(void *arg) {  
    int writer_id = *((int *)arg);  
    while (1) {  
        // 请求写入锁  
        sem_wait(&rw_mutex);  
  
        // 写入操作  
        printf("Writer %d is writing.\n", writer_id);  
        sleep(WRITE_TIME);  
  
        // 释放写入锁  
        sem_post(&rw_mutex);  
  
        sleep(1);  // 写者休息一会儿再尝试写入  
    }  
    return NULL;  
}  
  
int main() {  
    pthread_t readers[NUM_READERS], writers[NUM_WRITERS];  
    int reader_ids[NUM_READERS], writer_ids[NUM_WRITERS];  
  
    // 初始化信号量  
    sem_init(&rw_mutex, 0, 1);  
    sem_init(&mutex, 0, 1);  
  
    // 创建读者线程  
    for (int i = 0; i < NUM_READERS; i++) {  
        reader_ids[i] = i;  
        pthread_create(&readers[i], NULL, reader, &reader_ids[i]);  
    }  
  
    // 创建写者线程  
    for (int i = 0; i < NUM_WRITERS; i++) {  
        writer_ids[i] = i;  
        pthread_create(&writers[i], NULL, writer, &writer_ids[i]);  
    }  
  
    // 等待线程结束(实际上这些线程是无限循环的,这里只是为了示例)  
    for (int i = 0; i < NUM_READERS; i++) {  
        pthread_join(readers[i], NULL);  
    }  
    for (int i = 0; i < NUM_WRITERS; i++) {  
        pthread_join(writers[i], NULL);  
    }  
  
    // 销毁信号量  
    sem_destroy(&rw_mutex);  
    sem_destroy(&mutex);  
  
    return 0;  
}

信号量初始化:

  • rw_mutex:用于保护共享资源的互斥锁,初始值为1,表示资源可用。
  • mutex:用于保护读者计数read_count的互斥锁,初始值为1,表示可访问。

读者线程:

  • 使用sem_wait(&mutex)请求访问读者计数互斥锁。
  • 增加read_count,如果这是第一个读者,则请求rw_mutex锁,独占资源。
  • 释放mutex锁。
  • 执行读取操作。
  • 再次请求mutex锁,减少read_count,如果这是最后一个读者,则释放rw_mutex锁。
  • 释放mutex锁。

写者线程:

  • 直接请求rw_mutex锁,独占资源。
  • 执行写入操作。
  • 释放rw_mutex锁。

主函数:

  • 创建读者和写者线程。
  • 等待线程结束(这里示例代码中的线程是无限循环的,实际使用时可能需要加入退出条件)。
  • 销毁信号量

 2、利用信号量集机制解决读者-写者问题

使用了信号量(semaphores)来管理对共享资源的访问。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define NUM_READERS 5
#define NUM_WRITERS 3
#define READ_TIME 2
#define WRITE_TIME 1

sem_t rw_mutex;      // 保护共享资源的互斥锁
sem_t mutex;         // 保护读者计数的互斥锁
int read_count = 0;  // 当前正在读取的读者数量

void *reader(void *arg) {
    int reader_id = *((int *)arg);
    while (1) {
        sem_wait(&mutex);
        read_count++;
        if (read_count == 1) {
            sem_wait(&rw_mutex);
        }
        sem_post(&mutex);

        printf("Reader %d is reading.\n", reader_id);
        sleep(READ_TIME);

        sem_wait(&mutex);
        read_count--;
        if (read_count == 0) {
            sem_post(&rw_mutex);
        }
        sem_post(&mutex);

        sleep(1);
    }
    return NULL;
}

void *writer(void *arg) {
    int writer_id = *((int *)arg);
    while (1) {
        sem_wait(&rw_mutex);

        printf("Writer %d is writing.\n", writer_id);
        sleep(WRITE_TIME);

        sem_post(&rw_mutex);

        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t readers[NUM_READERS], writers[NUM_WRITERS];
    int reader_ids[NUM_READERS], writer_ids[NUM_WRITERS];

    sem_init(&rw_mutex, 0, 1);
    sem_init(&mutex, 0, 1);

    for (int i = 0; i < NUM_READERS; i++) {
        reader_ids[i] = i;
        pthread_create(&readers[i], NULL, reader, &reader_ids[i]);
    }

    for (int i = 0; i < NUM_WRITERS; i++) {
        writer_ids[i] = i;
        pthread_create(&writers[i], NULL, writer, &writer_ids[i]);
    }

    for (int i = 0; i < NUM_READERS; i++) {
        pthread_join(readers[i], NULL);
    }
    for (int i = 0; i < NUM_WRITERS; i++) {
        pthread_join(writers[i], NULL);
    }

    sem_destroy(&rw_mutex);
    sem_destroy(&mutex);

    return 0;
}

变量定义

  • NUM_READERS 和 NUM_WRITERS:分别定义了读者的数量和写者的数量。
  • READ_TIME 和 WRITE_TIME:分别定义了读者读取和写者写入共享资源所需的时间(以秒为单位)。
  • rw_mutex:一个信号量,用于保护对共享资源的访问,确保写者在写入时具有独占权。
  • mutex:一个信号量,用于保护对read_count(当前正在读取的读者数量)的访问,确保读者计数操作的原子性。
  • read_count:当前正在读取的读者数量。

读者线程(reader函数)

  • 每个读者线程首先获取mutex信号量,以确保对read_count的访问是原子的。
  • 然后,读者增加read_count的值。
  • 如果这是第一个读者(read_count == 1),它会获取rw_mutex信号量,以阻止写者和其他读者开始读取,直到当前读者组完成读取。
  • 释放mutex信号量,允许其他读者修改read_count
  • 读者开始读取(通过sleep(READ_TIME)模拟读取时间)。
  • 再次获取mutex信号量,准备修改read_count
  • 减少read_count的值。
  • 如果这是最后一个读者(read_count == 0),它会释放rw_mutex信号量,允许写者开始写入。
  • 释放mutex信号量。
  • 休眠一段时间(sleep(1)),然后重复上述过程。

写者线程(writer函数)

  • 每个写者线程首先获取rw_mutex信号量,以确保对共享资源的独占访问。
  • 写者开始写入(通过sleep(WRITE_TIME)模拟写入时间)。
  • 释放rw_mutex信号量,允许其他读者或写者访问共享资源。
  • 休眠一段时间(sleep(1)),然后重复上述过程。

主函数(main

  • 初始化rw_mutexmutex信号量。
  • 创建读者线程和写者线程,每个线程都运行其相应的函数(readerwriter)。
  • 使用pthread_join等待所有读者和写者线程完成(实际上,由于线程在一个无限循环中运行,这里的pthread_join会永远阻塞)。
  • 销毁rw_mutexmutex信号量。

注意

  • 这段代码中的读者和写者线程在一个无限循环中运行,这意味着程序永远不会自然结束。在实际应用中,你可能需要实现一种机制来优雅地停止这些线程。
  • 使用sleep函数来模拟读取和写入时间是出于简化的目的。在实际应用中,你可能会有更复杂的逻辑来处理读取和写入操作。
  • pthread_join的调用意味着主线程将等待所有读者和写者线程完成,但由于这些线程在无限循环中运行,程序将不会自然结束。

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

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

相关文章

WPF用户控件的使用

WPF用户控件的使用 先看一下程序结构&#xff1a; WPF_Test是我的主程序&#xff1b;WPF_LIB是我添加的一个用户控件库&#xff0c;其中UserControl1是一个用户控件&#xff1b; 用户控件xaml代码&#xff1a; <UserControl x:Class"WPF_LIB.UserControl1"xmln…

爵士编曲:爵士钢琴编写的规律和步骤 关于教程的个人想法 举一反三

反思了下自己目前学习编曲和其他兴趣爱好时暴露出来的问题&#xff0c;就是举一反三的能力还有待提高&#xff01;平时多学习和多对学习内容进行举一反三&#xff0c;也就是根据一个例子&#xff0c;创作出类似的3个以上的例子&#xff0c;这样才算学会&#xff0c;并且事半功倍…

2024必备英语在线翻译工具推荐

英语在线翻译工具就如同一位随时待命的语言助手&#xff0c;为我们打破语言障碍&#xff0c;搭建起沟通的桥梁。接下来&#xff0c;让我们一起深入了解这些英语在线翻译工具的丰富功能及其为我们带来的便利。 1.福昕在线翻译 链接直达>>https://fanyi.pdf365.cn/doc …

【含文档】基于Springboot+微信小程序 的海产品加工销售一体化管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

基于SpringBoot+Vue+MySQL的民宿预订平台

系统展示 用户前台界面 管理员后台界面 商家后台界面 系统背景 随着旅游业的蓬勃发展&#xff0c;民宿作为一种独特的住宿方式&#xff0c;受到了越来越多游客的青睐。然而&#xff0c;传统的民宿预定方式往往存在信息不对称、效率低下等问题&#xff0c;难以满足游客的个性化需…

python的内存管理机制

python的内存管理机制主要分为三个部分&#xff1a;引用计数、垃圾回收和内存池机制。 引用计数机制&#xff1a; python通过维护每个对象的引用计数来跟踪内存中的对象。当对象被创建时就会有一个引用计数&#xff0c;当对象不再被使用时&#xff0c;引用计数为0&#xff0c…

Android SystemUI组件(08)睡眠灭屏 锁屏处理流程

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分 睡眠灭屏 即可。 Power按键的处理逻辑最终是由PhoneWindowManager来完…

【电路基础 · 2】电阻电路的等效变换(自用)

总览 1.电路的等效变换 1.1 电阻电路 1.2 等效变换是什么 1.3 线性电路和非线性电路 1.4 时变电路和非时变电路 1.5 二端网络&#xff08;一端口网络&#xff09;、四端网络&#xff08;二端口网络&#xff09;、六端网络&#xff08;三端口网络&#xff09; 1.6 两端电路的等…

每日一题:二分查找

文章目录 一、思路一&#xff1a;常规思路1、寻找固定值2、寻找左边界3、寻找右边界 二、思路二&#xff1a;红蓝法二分三、模板题1、二分查找2、在排序数组中查找元素的第一个和最后一个位置 二分查找&#xff0c;顾名思义&#xff0c;就是每次筛选能晒掉一半的数据。 二分查…

leetcode每日一题day22(24.10.2)——准时到达的列车最小度

思路&#xff1a;这种在有约束条件情况下&#xff0c;求最值或最符合要求的情况&#xff0c;首先是很容易想到&#xff0c;从时速为1开始往后找找到满足条件就输出&#xff0c;但这无疑工程量很大&#xff0c;每种可能的速度都要对列车数组进行遍历&#xff0c; 时间复杂度为C…

数据库第8章编程题2

10-1 查询选修某两门课程的学生&#xff08;MSSQL) 本题目要求编写SQL语句&#xff0c; 检索出 sc表中至少选修了’C001’与’C002’课程的学生学号。 提示&#xff1a;MSSQLServer 评测SQL语句。 表结构: 请在这里写定义表结构的SQL语句。例如&#xff1a; -- 学生选课成…

Pikachu-Cross-Site Scripting-存储型xss

存储型xss &#xff0c;随便输入点内容&#xff0c;都能保存下来&#xff1b;刷新后也不会丢失&#xff1b;输入特殊字符&#xff0c;也能原样返回&#xff1b; 查看代码&#xff0c;也可以看到输出结果直接原路返回&#xff0c;不做处理 构造payload <script>alert(1)…

深度学习:cGAN和pix2pix图像转换

cGAN和pix2pix的基础概念 cGAN cGAN是条件生成对抗网络&#xff08;Conditional Generative Adversarial Networks&#xff09;的简称。 它是一种基于基础GAN&#xff08;Generative Adversarial Networks&#xff09;架构的变体&#xff0c;通过给GAN模型引入额外的信息或条…

翔云 OCR:发票识别与验真

在数字化时代&#xff0c;高效处理大量文档和数据成为企业和个人的迫切需求。翔云 OCR 作为一款强大的光学字符识别工具&#xff0c;在发票识别及验真方面表现出色&#xff0c;为我们带来了极大的便利。 一、翔云 OCR 简介 翔云 OCR 是一款基于先进的人工智能技术开发的文字识别…

酒店智能门锁SDK接口pro[V10] 门锁校验C#-SAAS本地化-未来之窗行业应用跨平台架构

一、代码 int 酒店标识_int Convert.ToInt32(酒店标识);StringBuilder 锁号2024 new StringBuilder(8);//信息 "未知返回值&#xff1a;" bufCard_原始;GetGuestLockNoByCardDataStr_原始(酒店标识_int, bufCard_原始.ToString(), 锁号2024);StringBuilder 退…

Pie-饼图

参考文档&#xff1a;Pie - Pie_set_color - Document (pyecharts.org) 模板 from pyecharts import options as opts from pyecharts.charts import Pie from pyecharts.faker import Faker"""1-Pie() 创建Pie对象2-.add("", [list(z) for z in zi…

CSS 圆形边框与阴影

目录 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影

CSS盒子模型基础知识(23个案例+代码+效果图)

目录 1.边框样式 案例&#xff1a;制作一个边框为实线的正方形 1&#xff09;代码​编辑 2&#xff09;效果 案例&#xff1a;制作一个边框为虚线的正方形 1&#xff09;代码 2&#xff09;效果 案例&#xff1a;制作一个边框为点线的正方形 1&#xff09;代码 2&#xff09;效…

二分查找一>:在排序数组中查找元素的第一个和最后一个位置

1.题目&#xff1a; 2.解析:这里不能用传统二分&#xff0c;因为涉及范围&#xff0c;传统二分时间复杂度会降为O(N)&#xff0c;要做些改动。 步骤一&#xff1a;查找区间左端点 细节图&#xff1a; 步骤二&#xff1a;查找区间右端点&#xff1a; 细节图&#xff1a; 代码…

Cpp::STL—vector类的使用与理解(上)(10)

文章目录 前言一、vector的介绍三个原生指针的图示 二、vector的构造函数一个注意事项 二、vector的空间大小、调整函数size()capacity()empty()resize()reserve() 三、vector的增删查改push_back & pop_backinsert & erasefindswapfront & backoperator[ ] & …