Linux系统---图书管理中的同步问题
顾得泉:个人主页
个人专栏:《Linux操作系统》 《C/C++》 《LeedCode刷题》
键盘敲烂,年薪百万!
一、问题描述
(1)图书馆阅览室最多能够容纳N(N=5)名学生,若有更多学生想进入阅览室,必须等到阅览室中有同学退出之后才能进入。
(2)阅览室有一名管理员。早到的同学必须等管理员开门之后才能进入,管理员必须等到所有同学都退出之后才能关门。
请你用信号量实现上述问题。
二、问题分析
(1)将在“阅览室读书”看做一个临界区,该临界区最多只允许N名学生进入。把每个“学生”建模为一个线程,这是一个互斥问题。于是可以设计一个初值为N的信号量,实现互斥。
(2)管理员需要与第一个学生同步,即第一个学生等待管理员开门;管理员也需要与最后一名学生同步,即管理员等待最后一名学生退出之后,才能关闭图书馆。因此可以实现一个学生计数,实现条件同步。
三、命名规则
(1)用Student和Manager分别表示学生和管理员线程名。
(2)Student包括三个操作:Checkin( )(刷入)、Reading( )(阅读)、checkout( )(刷出)
(3)Manager包括三个操作:OpenDoor( )(开门)、CloseDoor( )(关门)、manage( )
四、具体实现
1. test.c文件
test.c文件是一个模拟学生进出教室的多线程程序。它使用了信号量(semaphore)来实现同步和互斥。
首先,定义了一些全局变量:
ns
表示当前正在教室的学生数量。mutex
用于保护对ns
的访问。room
用于限制教室的最大容量。wfm
和wfs
分别表示等待进入教室和等待离开教室的信号量。fetch
表示等待学生进入教室的信号量。flag
表示是否已经有学生进入教室。
接下来,定义了两个函数:
student(void* i)
是每个学生的线程函数。它接收一个参数i
,表示学生的编号。manager(void *arg)
是管理线程的函数。它不需要参数。
在 student
函数中,首先打印出学生进入教室的信息。然后,通过调用 P(&fetch)
来请求获取 fetch
信号量,表示有学生准备进入教室。接着,通过调用 P(&mutex)
来请求获取 mutex
信号量,以保护对 ns
的访问。然后,根据当前的学生数量和是否有学生已经进入教室,执行相应的操作。最后,释放 mutex
信号量,并通过调用 sleep(1)
让当前线程暂停一段时间,模拟学生进入教室的过程。然后,打印出学生离开教室的信息,并释放其他信号量和变量。
在 manager
函数中,首先打印出管理打开教室的信息。然后,通过调用 V(&wfm)
来释放 wfm
信号量,表示有学生可以进入教室。接着,打印出管理等待所有学生离开教室的信息。然后,通过调用 P(&wfs)
来请求获取 wfs
信号量,表示所有学生都已经离开教室。最后,打印出管理关闭教室的信息。
在 main
函数中,首先初始化了所有的信号量。然后,创建了多个学生线程,每个线程对应一个学生编号。接着,创建了一个管理线程。最后,使用 pthread_exit(NULL)
退出主线程。
#include<semaphore.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include"ch4-PV.h"#define N 5unsigned int ns = 0;
sem_t mutex;
sem_t room;
sem_t wfm;
sem_t wfs;
sem_t fetch;
int flag = 0;void *student(void* i)
{int id = (int)i;printf("Student %i is entring...\n",id);P(&fetch);ns++;P(&mutex);if(ns == 1 && flag ==0){P(&wfm);P(&room);flag = 1;printf("The 1st student %i has been entered.\n",id);}else{P(&room);printf("The student %i has been entered\n",id);}V(&mutex);sleep(1);printf("The student %i is going to leave...\n",id);P(&mutex);ns--;if(ns == 0){V(&wfs);printf("The last student left.\n");}elseprintf("The student %i has left.\n",id);V(&room);V(&mutex);V(&fetch);
}void *manager(void *arg)
{printf("The manager opens the door.\n");V(&wfm);printf("The manager is waiting for all student leaves.\n");P(&wfs);printf("The manager closes the door.\n");
}int main()
{sem_init(&wfm,0,0);sem_init(&fetch,0,5);sem_init(&wfs,0,0);sem_init(&mutex,0,1);sem_init(&room,0,5);pthread_t tid;for(int i = 1; i <= N; i++)pthread_create(&tid,NULL,student,(void *)i);pthread_create(&tid,NULL,manager,(void *)NULL);pthread_exit(NULL);return 0;
}
2. ch4-PV.c文件
这段代码是一个简单的信号量实现,用于实现生产者消费者问题。其中包含了两个函数:P() 和 V()。
- P(sem_t *s) 函数用于等待信号量。如果信号量的值大于0,则将信号量的值减1并返回;否则,该函数会阻塞,直到信号量的值变为大于0。
- V(sem_t *s) 函数用于释放信号量。将信号量的值加1,并唤醒一个等待该信号量的线程。
#include<stdio.h>
#include<semaphore.h>
#include<stdlib.h>
#include"ch4-PV.h"void P(sem_t *s)
{if(sem_wait(s)<0)printf("P error");
}void V(sem_t *s)
{if(sem_post(s)<0)printf("V error");
}
3. ch4-PV.h文件
这段代码定义了相应的头文件。
#include<semaphore.h>
#include<unistd.h>void P(sem_t *s);
void V(sem_t *s);
4. makeflie文件
这是一个Makefile文件,用于编译和清理生成的可执行文件和目标文件。(之前的文章对此有过相应的讲解)
test:test.o ch4-PV.ogcc -pthread test.o ch4-PV.o -o test
tets.o:test.cgcc -c test.c
ch4-PV.o:ch4-PV.cgcc -c ch4-PV.c
.PHONY:cleanclean:rm -rf ch4-PV.orm -rf testrm -rf test.o
五、实现结果
首先进行make操作:
进行查看是否编译:
运行文件:
进行make clean操作:
到此一个简单的图书馆同步问题就实现了。
结语:Linux系统关于图书管理同步问题的分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言~~~
相关文章:

Linux系统---图书管理中的同步问题
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、问题描述 (1)图书馆阅览室最多能够容纳N(N5)名学生,若有更多学生想…...
Vue学习笔记-activated和deactivated生命周期
作用 路由组件所独有的2个生命周期 activated生命周期函数用于在路由组件每次由消失到出现时所调用的函数deactivated生命周期函数用于路由组件每次由出现到消失时(无论是否缓存)所调用的函数 案例 定义一个NewsVue组件,要求:…...

102.套接字-Socket网络编程4(TCP通信流程)
目录 TCP编程流程 套接字函数 1.创建套接字 2.绑定地址 3.监听连接请求 4.接受连接 5. 连接到服务器 6. 发送数据 7. 接收数据 8.关闭套接字 服务器端通信流程 示例代码 客户端通信流程 代码示例 TCP编程流程 TCP是一个面向连接的,安全的,流…...

spring boot 2 升级到 spring boot 3 后文件上传失败
背景 项目需要,要求升级 spring boot 2.7 到 spring boot 3.2,升级过程中发现很多不兼容问题,下面说明文件上传失败的解决方案。 问题 spring boot 2 中不需要额外的配置,直接在 Controller 中配置 MultipartFile 接收页面传的…...
Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异,并取出不同的对象
Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异,并取出不同的对象。这可以通过使用 distinct() 和 filter() 方法来实现。 假设我们有两个 List,一个是 list1,另一个是 list2,我们想找出 list1 中存在但 list2…...
C语言还会存在多久
一、C语言的生命力 在当前的科技发展和就业市场需求下,可以肯定地说C语言并没有像一些新兴语言(如Python、JavaScript等)那样受到大量的关注。然而,并不意味着学习C语言的人会越来越少。 首先,C语言作为一种深受尊重…...

手持式安卓主板_PDA安卓板_智能手持终端方案
手持式安卓主板方案是一种智能终端设备,具备自动对焦和闪光灯功能,可以在昏暗的环境下快速扫描二维码并轻松采集数据。该方案还提供多渠道支付和数据采集功能,为用户提供了便捷的体验。 该方案的产品基于手持式安卓主板,并搭载了八…...
LeetCode103. Binary Tree Zigzag Level Order Traversal
文章目录 一、题目二、题解 一、题目 Given the root of a binary tree, return the zigzag level order traversal of its nodes’ values. (i.e., from left to right, then right to left for the next level and alternate between). Example 1: Input: root [3,9,20,n…...
PHP 判断给定两个时间是否在同一周,月,年
判断是否在同一周 date_default_timezone_set(PRC); //判断是否在同一周,原理:求出其中一个时间戳所在周的周一凌晨时间戳和周日24.00时间戳,如果另一个时间戳在这个范围内,则说明在同一周,否则不在同一周 function g…...

单机无锁线程安全队列-Disruptor
Disruptor 1、基本介绍 说到队列,除了常见的mq中间件,java中也自带线程安全的BlockingQueue,但是BlockingQueue通过在入队和出队时加锁的方式避免并发操作,性能上会大打折扣。 而Disruptor是一个线程安全、低延迟、吞吐量高的队…...
好工具知多少:国内外最常用的SCADA软件
随着现代SCADA系统的发展,工业自动化取得了巨大的飞跃。如今,监控和数据采集(SCADA)系统已成为工业过程的重要组成部分。这些系统使操作员能够实时监控和控制复杂的系统。 SCADA系统正在广泛的行业中发挥着至关重要的作用&#x…...

SQL Server 2016(创建数据库)
1、实验环境。 某公司有一台已经安装了SQL Server 2016的服务器,现在需要新建数据库。 2、需求描述。 创建一个名为"db_class"的数据库,数据文件和日志文件初始大小设置为10MB,启用自动增长,数据库文件存放路径为C:\db…...
Vue学习计划--Vue2(一)简单了解vue
Vue2的终止支持时间为2023年12月31日。 在这个矛盾的时间点,还是决定先把vue2的笔记放出来,在Vue2完结后再把Vue3的笔记补上。这样呢,2和3都不落下,也算是来一个启承的作用吧。在工作中呢,旧的项目可以维护,…...

微信小程序生成二维码并保存到本地方法
微信小程序生成二维码请保存到本地方法 官方weapp-qrcode插件 github链接 功能完成样子 wxml <view class"qrcode"><canvas style"width: 275px; height: 275px;" canvas-idmyQrcode></canvas> </view> <view class" …...
shell_exec 和 exec区别
shell_exec 和 exec 都是用于在 PHP 中执行系统命令的函数,但它们之间有一些区别。 返回值类型:shell_exec 函数返回命令的输出结果作为字符串,而 exec 函数将输出结果存储在数组中。 输出结果:shell_exec 函数返回命令的完整输出…...

WPF创建进度条
使用wpf做一个原生的进度条,进度条上面有值,先看效果。 功能就是点击按钮,后台处理数据,前台显示处理数据的变化,当然还可以对进度条进行美化和关闭的操作,等待后台处理完毕数据,然后自动关闭。…...

全网最新最全面的Appium自动化:Appium常用操作之混合应用webview页面操作--待补充!
上下文操作: 在appium中,对于混合应用,需要进行WebView页面和原生应用的切换 常用的方法如下: 1、context(self) / current_context(self):返回当前会话的当前上下文,context可以理解为可进入的窗口。对于…...

基于OpenCV+YOLOv5实现车辆跟踪与计数(附源码)
导 读 本文主要介绍基于OpenCVYOLOv5实现车辆跟踪与计数的应用,并给出源码。 资源下载 基础代码和视频下载地址: https://github.com/freedomwebtech/win11vehiclecount main.py代码: import cv2import torchimport numpy as npfrom tr…...

05、pytest断言确定的异常
官方用例 # content of test_sysexit.py import pytestdef f():raise SystemExit(1)def test_mytest():with pytest.raises(SystemExit):f()解读与实操 标准python raise函数可产生异常。pytest.raises可以断言某个异常会发现。异常发生了,用例执行成功&#x…...

金蝶云星空单据编辑界面,不允许批量填充操作
文章目录 金蝶云星空单据编辑界面,不允许批量填充操作案例演示开发设计测试 金蝶云星空单据编辑界面,不允许批量填充操作 案例演示 售后单,明细信息单据体,物料编码字段禁止批量填充。 开发设计 编写表单插件,在Be…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...

Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...