Linux—C++实现多线程读写者问题

362 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

1. 背景介绍

本篇文章是笔者在大二时进行操作系统实验时写下的多线程编程总结,使用的是Linux的Ubuntu系统。

由于本人对于Linux也并非很熟练,所以有些细节方面有错误也恳请各位的包容与理解

本次实验需要涉及到的工具:

  • g++编辑器——用于编译cpp文件
  • vim编辑器——用于更好地编写文件代码内容

涉及到的库:

  • thread——用于创建线程即线程队列
  • mutex——用于创建信号量,同时支持锁定及解锁

2. 工具安装

安装g++编辑器

  • 首先登录root用户

打开终端,快捷键:Ctrl+Alt+T

请求登录root用户命令:

su root

然后输入密码回车即可登录

注意:这里可能会有些萌新小伙伴未设置root的密码,此时需要先设置其密码

Linux系统在输入密码时是不可见的

然后我们继续登录:

我们会发现,$符号代表着普通用户,而#代表着root用户

刚登录时目录默认在home下的当前登录虚拟机的用户文件夹下

  • 开始安装g++编辑器

命令:apt install g++

因为我这里已经下载过g++,所以显示的内容不一样

另外vim编辑器在我印象里Linux系统是有自带的,所以不需要安装,如果没有的话也可以直接指令apt install vim安装

3. 熟悉g++编译cpp文件步骤

  • 我们先来在文档目录下创建一个test文件夹并创建test.cpp文件

在创建文件时先指定后缀名,以此在编写c++代码时能够有高亮,方便编写

在文件里编写一段小小的测试代码:

  • 接下来就是最重要的一步:编译文件

g++ test.cpp -o TEST

编译成功后输入ls指令就会发现目录里多了个TEST,如果希望启动该程序,只需要输入./TEST即可

以上就是在Linux编写运行C++程序的基本步骤,接下来就要开始编写多线程编程了

4. 多线程编程

我们还是在test目录下创建一个新文件,然后通过vim编辑器进行编写,我们分为三个算法程序,读者优先,读写公平和写者优先

1. 读者优先算法

  1. 首先创建读者优先.cpp文件

  1. 编写代码

引入头文件时需要同时引入threadmutex,前者是用于创建线程的,后者则是用于创建信号量的

同时定义READ READEND WRITE WRITEEND函数,用于显示读写状态

然后需要定义上锁和解锁函数PV,用于处理信号量

读者的read函数

注意这里对cnt信号量量进行互斥处理是为了防止多个读者线程同时对count进行修改或读取判断,造成信息读取有误

当读取前count为0时,说明该读者线程为线程队列中的第一个读者,需要对共享文件进行上锁,即将rw信号量上锁

当读取后count为0时,说明该读者线程为线程队列中的最后一个读者,需要对rw进行解锁

因此只要读者列表还没空,一有读者线程来到,就会立即加入队列,不会被阻塞,这就是读者优先的体现

写者的write函数

write函数则只是简单地对rw进行上锁和解锁

主函数

利用thread创建多个读写线程,让他们去调用readwrite函数,同时传入自己的名字作为参数

利用线程身上的join函数依次加入队列

  1. 编译文件并运行

注意这里在编译的时候需要添加 -lpthread参数

2. 读者写者公平算法

  1. 创建读写公平.cpp文件并进行编辑,创建命令参考读者优先算法
  2. 该算法与读者优先算法的不同之处是多设置了一个w信号量,用于防止写者线程饥饿,并且在write函数和read函数中增加了对w的上锁和解锁步骤

read函数

这里在读者线程进入队列之前,会先访问w信号量,如果此时有写者已经将w上锁,该读者线程将会被阻塞,因此写者线程不会出现饥饿

write函数

其他部分代码与读者优先算法相同

  1. 编译文件并运行

3. 写者优先算法

  1. 创建写者优先.cpp文件并进行编辑,创建命令参考读者优先算法
  2. 该算法相对于读写公平算法为写者线程增加了一个wcount计数变量以及对应的wcnt信号量,还有一个用来阻塞读者线程的r信号量

P、V函数

read函数

read函数中如果读者想要进入队列需要查看r是否被锁定,如果r被锁定则读者线程被阻塞,即此时写者线程优先

write函数

当写者线程队列不为空时,将始终保持r信号量为锁定状态,此时读者线程也将还一直保持阻塞状态,这是写着优先的体现

主函数

  1. 对文件进行编译及运行