操作系统实验二 进程(线程)同步

news2024/11/27 20:26:44

前言

实验二相比实验一难度有所提升,首先得先掌握好相应的理论知识(读者-写者问题和消费者-生产者问题),才能在实验中得心应手。任务二的代码编写可以借鉴源码,所以我们要先读懂源码。

1.实验目的

掌握Linux环境下,进程(线程)同步以及临界资源的互斥访问方法。

2.实验要求

熟悉Linux操作系统线程创建、利用信号量机制进行同步和互斥访问临界资源。

3.实验内容

本实验包含生产者和消费者之间的同步以及读者和写者之间的同步两部分,请实现以下功能:

  1. 多个生产者多个消费者线程。我们使用含有n个元素的数组表示n个缓冲区生产者线程每间隔一段时间例如一秒钟生产一个产品放入缓冲区中。消费者线程等待生产者线程放入产品后在缓冲区中取出产品。请使用信号量机制实现生产者线程和消费者线程之间的同步。(生产者消费者)
  2. 有一个或多个写者线程多个读者线程。读者和写者之间共享一缓冲区(缓冲区可用字符数组表示),写者获得缓冲区访问权限后往缓冲区写入内容。读者获得缓冲区访问权限后从缓冲区中读出内容。当有一个读者获得缓冲区访问权限后,其它读者线程可以访问该缓冲区。而读者与写者之间需要互斥的访问缓冲区。

4.实验的内容与过程

阅读代码

在实验前,我们先把代码理清楚。

mainProg.c

解析:在mainProg.c中,我们根据定义的生产者和消费者数量生成了相应的空间大小。紧接着,我们又定义了一个生产者消费者管理者,这个的主要作用是管理临界资源。(后面我会分析)接着就是两个for循环,一个for循环是调用两个生产者执行生产任务,一个for循环是调用消费者执行消费任务。在这两个循环中,我们都用到了pthread_create函数,这个函数主要作用是创建以第三个参数start_routine为入口函数的线程。传入的四个参数分别为:线程的指针、线程属性、线程运行函数起始地址、传入到运行函数的参数。也就是生产者的for循环中产生的子线程完成producerThread函数中的任务,消费者的for循环中产生的子线程完成consumerThread函数中的任务。

producerThread在Producer.c文件中

 

解析:ProducerThread函数中,先获取了我们的临界资源,然后随机生成种子数,为我们后面生成随机数做准备。接着在while循环中生产产品,直到exit_flag变成1,我们才不继续生产产品。生产产品我们主要调用了自定义的generateProduct函数。在generateProduct函数中,我们先将三个信号赋值上相应的数值,然后随机生成一个随机数,也就是我们的产品。接着调用semwait (empty)和semWait(mutex)。我们应该注意把semwait (empty)放在 semWait(mutex)前面,否则会产生死等现象。接着现有产品数量+1,再把产品放到缓存区中,并输出相应的信息。最后我们在线程结束后,调用semsignal释放信号。

consumerThread在Consumer.c文件中

 

解析:consumerThread函数跟上面的ProducerThread函数类似,并且图中也有注释,我就不详细介绍了。接着就是getProduct函数。在函数中,先将三个信号赋值上相应的数值,然后调用semwait (full)和semWait(mutex)并取出一个商品,然后产品数量减1并打印出相应的信息。最后我们在线程结束后,调用semsignal释放信号。

ProducerConsumerUtilities.c文件:

        

 

 解析:在这个文件中,通过截屏中的注释,我们发现这个文件中无非是定义了一堆初始化和自定义的创建线程的方法,接着就是wait、signal、摧毁操作,方便我们在其他地方调用这些方法。

ProducerConsumerUtilities.h文件:

 

解析:在这个文件中定义了生产者消费者管理者这个结构体,其内容主要有记录mutex、full、empty这三个信号,生产者的偏移量,消费者的偏移量,现有产品的数量,缓存区,缓存区大小以及判断是否结束的变量。之所以定义这个结构体,是因为这些资源都是公共资源,即临界资源,是各个线程一起使用的。然后就是线程结构体和一些方法的声明。

至此,我们的代码关键部分基本已经分析完毕了,对实验的原理已经有了一定的了解,接下来就可以开始实验了。

任务1.写出生产者消费者程序对应Makefile

Makefile文件

 解析:根据我们的现有文件生成对应的.o文件,即第三行的文件名。(注意第二行的CFLAGS变量中加入-lpthread)

运行结果:

 可以看到,我们的生产者消费者程序已经可以运行了,输入q即可停止。(因为mainProg中定义了我们输入q的话exit_flag会变成1)

至此,我们的任务一就完成了,接下来就是任务二。

任务2:读者写者程序

mainProg.c

 解析:定义了2个写者和6个读者后(个数自行定义),给相应的线程分配足够的空间,并生成一个读者写者的管理者,用来管理临界资源。接着就是写者线程和读者线程的初始化,和生产者消费者的代码大同小异,主要还得看下面部分的代码。

ReaderWriterUtilities.h文件:

解析:这个头文件主要定义了读者写者程序的管理者的一些方法和结构。首先是读者写者管理者的结构体。这个结构体里面有信号量mutex和rmutex(mutex信号用来实现互斥访问缓冲区,rmutex信号主要用来实现互斥访问readcount变量),还有readcount变量用来存放读者的数量,buffer数组用来存放字符,类似于写者的作品。还有buffersize用来记录缓存区大小,exit_flag来确定线程的状态。接着是线程结构体还有一些方法的定义。由于这些内容跟生产者消费者的代码部分大同小异,就不再赘述。

ReaderWriterUtilities.c文件: 

 

 解析:可以看到,在这个文件中,主要是定义了一堆初始化和自定义的创建线程的方法,接着就是wait、signal、摧毁操作,跟任务一代码类似并且截屏中已有注释,不赘述。接下来就是关键的读者部分和写者部分代码了。

Reader.c文件:

 分析:先看看在这个文件中定义的read_data方法。这个方法主要先获取mutex信号、rmutex信号和readcount的值。然后定义了buf数组,用来存放作品的内容。接着,先使用wait语句来保证线程可以互斥访问readcount变量。如果readcount的值为0则说明当前没有读者在阅读作品,就先互斥访问临界资源来保证读者写者不会同时对临界资源进行操作(类似于第一个读的人要先去把作品拿过来),接着就是将readcount数量加1并且释放掉rmutex信号。当读者阅读完后,我们先互斥访问readcount,将readcount先减1,如果readcount的值为0,说明现在是最后一个读者,要释放掉mutex信号(类似于最后一个读完的人要归还作品),接着再释放掉rmutex信号。文件中定义的另一个方法readerThread则是实现读者线程的运行,如果exit_flag为0,则一直进行读操作。

Writer.c文件:

分析:先看这个文件中定义的write_data方法。在方法中,先获取mutex信号的值,然后调用wait方法,保证临界资源的互斥访问。接着,就在循环中往缓冲区写入字符,先随机获得一个偏移量(0到26),然后这个偏移量加上字符‘a’的ASCII码值就能得到‘a’到‘z’的一个字符。当我们把缓冲区填完了,就实现了一个写者的书写任务,接着就输出相应的信息并释放掉mutex信号。另一个方法writerThread方法则是实现写者线程的运行,当exit_flag的值为0时就一直执行写操作。

makefile文件:

 解析:生成文件为ReaderWriterUtilities.o、Writer.o、Reader.o和mainProg.o,在第三行填入即可,跟任务一操作类似。

运行结果:

 可以看到,我们的读者写者程序已经可以运行了,输入q即可停止。(因为mainProg中定义了我们输入q的话exit_flag会变成1)。通过观察,我们发现读者阅读的内容总跟最近一个写者书写的内容一样,说明代码是没问题的。

至此,我们的任务二也完成了。

要注意的是,writer.h和reader,h这两个头文件我没截屏出来,自己编写就行了,很简单的,仿照任务一的代码即可。

至此,我们的实验大功告成!如果大家有什么想法,可以在评论区提出,一起交流。

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

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

相关文章

linux系统状态检测命令

1、ifconfig命令 用于获取网卡配置于状态状态的等信息: ens33:网卡名称 inet:ip地址 ether:网卡物理地址(mac地址) RX、TX:接收数据包与发送数据包的个数及累计流量 我们也可以直接通过网卡名称查对应信息: 2、查看系统版本的…

设计模式 - 工厂 Factory Method Pattern

文章参考来源 一、概念 创建简单的对象直接 new 一个就完事,但对于创建时需要各种配置的复杂对象例如手机,没有工厂的情况下,用户需要自己处理屏幕、摄像头、处理器等配置,这样用户和手机就耦合在一起了。 可以使代码结构清晰&a…

【人工智能】— 贝叶斯网络

【人工智能】— 贝叶斯网络 频率学派 vs. 贝叶斯学派贝叶斯学派Probability(概率):独立性/条件独立性:Probability Theory(概率论):Graphical models (概率图模型)什么是图模型(Grap…

【每日一题/哈希表运用题】1054. 距离相等的条形码

⭐️前面的话⭐️ 本篇文章介绍【距离相等的条形码】题解,题目标签【哈希表】, 【贪心】,【优先级队列】,展示语言c/java。 📒博客主页:未见花闻的博客主页 🎉欢迎关注🔎点赞&#…

【计算机网络复习】第四章 网络层 2

源主机网络层的主要工作 路由器网络层的主要工作 目的主机网络层的主要工作 网络层提供的服务 o 屏蔽底层网络的差异,向传输层提供一致的服务 虚电路网络 o 虚电路网络提供面向连接的服务 n 借鉴了电路交换的优点 n 发送数据之前,源主机和目的主机…

MTK耳机识别

MTK耳机检测分为Eint only和EintAccdet 其中主流的是Eint Accdet(multi-key)。 图为MTK 耳机相关电路图的主要部分。 其中,左右声道的33pF主要滤除TDD干扰。串的10R100nf下地电容为低通滤波器。磁珠主要影响的是Fm以及音频THD性能。 Eint:检测耳机是否…

网络基础知识(3)——初识TCP/IP

首先给大家说明的是,TCP/IP 协议它其实是一个协议族,包含了众多的协议,譬如应用层协议 HTTP、 FTP、MQTT…以及传输层协议 TCP、UDP 等这些都属于 TCP/IP 协议。 所以,我们一般说 TCP/IP 协议,它不是指某一个具体的网络…

Casdoor 开始

Casdoor 是一个基于 OAuth 2.0 / OIDC 的中心化的单点登录(SSO)身份验证平台,简单来说,就是 Casdoor 可以帮你解决用户管理的难题,你无需开发用户登录、注册等与用户鉴权相关的一系列功能,只需几个步骤进行…

C++多线程中共享变量同步问题

目录 1、互斥量 (1)std::mutex (2)std::recursive_mutex (3)std::timed_mutex 2、锁管理器 (1)std::lock_guardlk (2)std::unique_locklk &#xff0…

掌控MySQL并发:深度解析锁机制与并发控制

前一篇MySQL读取的记录和我想象的不一致——事物隔离级别和MVCC 讲了事务在并发执行时可能引发的一致性问题的各种现象。一般分为下面3种情况: 读 - 读情况:并发事务相继读取相同的记录。读取操作本身不会对记录有任何影响,不会引起什么问题&…

【C++】C++中的多态

目录 一.多态的概念二.多态的定义及实现2.1虚函数2.2虚函数的重写虚函数重写的两个例外 2.3多态的构成条件2.4C11 override 和final2.5重载、重写、隐藏的对比 三.抽象类3.1概念3.2接口继承和实现继承 四.多态的原理4.1虚函数表4.2多态的原理(1)代码分析(2)清理解决方案 4.3动态…

MySQL高阶语句与连接

目录 高级查询selectDISTINCTWHEREAND ORINBETWEEN通配符与likeORDER BY数学函数聚合函数字符串函数mysql进阶查询GROUP BYHAVING别名子查询EXISTS连接查询inner join(内连接)left join(左连接)right join(右连接)自我连接 高级查询 实验准备: 第一张表&#xff1a…

Cesium入门之六:Cesium加载影像图层(ArcGIS、Bing、Mapbox、高德地图、腾讯地图、天地图等各类影像图)

Cesium加载影像图层 一、ImageryLayer类常用属性常用方法 二、ImageryLayerCollection类常用属性常用方法 三、ImageryProvider类常用属性常用方法 四、ImageryProvider子类1. ArcGisMapServerImageryProvider加载ArcGIS地图服务 2. BingMapsImageryProvider加载BingMap地图服务…

call to non-‘constexpr‘ function

文章目录 call to non-constexpr function概述备注END call to non-‘constexpr’ function 概述 在尝试迁移 openpnp - Smoothieware project 从gcc命令行 MRI调试方式 到NXP MCUXpresso工程. 在加了头文件路径后, 还有一些语法错误. 这和编译器语法有关系. 在运行BuildShe…

阿里云服务器部署flask项目「gunicorn + nginx + 支持https」

最近做了一个微信小程序,使用 flask 实现了对应的后台,上线需要部署到服务器上,之前只是了解并没有全链路试过,靠着网上的资料最终完成部署上线,但中间遇到了较多的一些问题,网上的资料也比较零碎&#xff…

WPF MaterialDesign 初学项目实战(2)首页导航栏样式

其他内容 WPF MaterialDesign 初学项目实战(0):github 项目Demo运行 WPF MaterialDesign 初学项目实战(1)首页搭建 MaterialDesign 确保运行了初学项目实战(0) MaterialDesign给我们提供了很多的样式库&…

微服务框架【笔记-Nacos环境隔离】

Nacos注册中心 环境隔离 - namespace Nacos 中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离 Nacos默认的命名空间: 创建命名空间复制命名空间ID启动Orderservice服务,在nacos服务列表可以看到环境隔离之后的服…

vue实现电梯锚点导航

1、目标效果 最近喝了不少的咖啡、奶茶,有一个效果我倒是挺好奇怎么实现的: (1)点击左侧分类菜单,右侧滚动到该分类区域 (2)右侧滑动屏幕,左侧显示当前所处的分类区域 这种功能会出现…

Jmeter进阶使用:BeanShell实现接口前置和后置操作

一、背景 我们使用Jmeter做压力测试或者接口测试时,除了最简单的直接对接口发起请求,很多时候需要对接口进行一些前置操作:比如提前生成测试数据,以及一些后置操作:比如提取接口响应内容中的某个字段的值。举个最常用…

XDC约束技巧 之 I/O篇 (上)

《XDC约束技巧之时钟篇》中曾对I/O约束做过简要概括,相比较而言,XDC中的I/O约束虽然形式简单,但整体思路和约束方法却与UCF大相径庭。加之FPGA的应用特性决定了其在接口上有多种构建和实现方式,所以从UCF到XDC的转换过程中&#x…