采用“写优先”的策略演示“读者-写者”问题(C - )

更新时间:2024-03-05 05:59:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

青岛理工大学

操作系统课程设计报告

院(系): 计算机工程学院 专业: 计算机科学与技术专业 学生姓名: 滕同学 班级:__软件102_ 学号: 201007195 题目: 采用“写优先”的策略演示“读者-写者”问题

起迄日期: 2013.7.8-2013.7.17

设计地点: 网络中心计算机学院机房 指 导 教 师: 吴老师

2012—2013年度 第 2 学期 完成日期: 2013 年 7 月 17 日

0

一、 课程设计目的

进行操作系统课程设计主要是在学习操作系统课程的基础上,在完成操作系统各部分实验的基础上,对操作系统的整体进行一个模拟,通过实践加深对各个部分的管理功能的认识,还能进一步分析各个部分之间的联系,最后达到对完整系统的理解。同时,可以提高运用操作系统知识解决实际问题的能力;锻炼实际的编程能力、创新能力及团队组织、协作开发软件的能力;还能提高调查研究、查阅技术文献、资料以及编写软件设计文档的能力。

此次实验我选择的是经典的读者写者问题。读写者问题的传统解决方案采用读优先策略,可能会造成后续的写者被随后而来的读者插队而长时间等待,直到全部读者进程运行完毕后,才可进行写操作。为此,选择采用“写优先策略”解决读写者问题,希望通过此次课程设计实现利于写者工作的功能,加深对线程、进程及同步概念的理解。通过研究经典的进程同步问题,实现对读者-写者问题的并发控制,掌握运用信号量解决“同类进程多次访问,而不同类的进程必须互斥访问资源”的控制问题。

此次实验我选择用比较大众的C#语言编写,因为C#中有semaphore类是对操作系统的semaphore很好的描述。

二、 课程设计内容与要求

1、设计目的:通过研究经典的进程进步问题,实现对读者-写者问题的并发控制。 2、说明:阅览室一次最多可以容纳20个人。 3、设计要求:

1) 读者与写者至少包括ID、进入内存时间、读写时间三项内容,可在界面上进行输入 2) 读者与写者均有二个以上,可在程序运行期间动态增加读者与写者 3) 可读取样例数据(要求存放在外部文件中),进行读者/写者、进入内存时间、读写

时间的初始化

4) 要求将运行过程用可视化界面动态显示,可随时暂停,查看阅览室中读者/写者数目、

读者等待队列、写者等待队列、读写时间、等待时间

5) 读写策略为:读写互斥、写写互斥、写优先(只要写者到达,就阻塞后续的所有读

者,一旦阅览室无人,写者能最快进入阅览室;在写者未出阅读室之前,又有新的读者与写者到达,仍然是写者排在前面)

三、 系统分析与设计

3.1 系统分析

3.1.1 信息分析:

写者优先程序实现写者优先进行写,本程序主要功能包括增加读者写者,时间的显示,动态的显示读写过程,暂停继续。具体实现这些功能所需要的信息表示如下:

1)读者线程信息:

public string Id;//读者线程ID

public int IncomeTime;//进入内存的时间 public int ServerTime;//需要服务的时间

2)写者线程信息:

1

public string Id;//写者线程ID

public int IncomeTime;//进入内存的时间 public int ServerTime;//需要服务的时间

3)计时器线程 (需要的变量)

public static DateTime initTime = new DateTime();//开始时系统时间 public static int uptime = 0;//系统暂停的全部时间 public static DateTime pause;//暂停时的时间 public static DateTime goon;//暂停结束的时间

2)主类中的信息:

public static int Rcount = 0;//阅览室内读者的人数 public static int Wcount = 0;//阅览室内写者的人数

public static DataTable rwq = new DataTable();//读者等待队列 public static DataTable wwq = new DataTable();//写者等待队列

public static Label lb1, lb2;//读者写者要访问的控件设置为静态全局变量: //lb1显示 当前是读者,还是写者

//lb2显示当前阅览室的人数 3)信号量信息:

public static Semaphore Mut1 = new Semaphore(1, 1);//实现写者优先的信号量 public static Semaphore Mut2 = new Semaphore(1, 1);//访问读者数量的信号量 public static Semaphore Fmutex = new Semaphore(1, 1);//表示浏览室的信号量

public static Semaphore rNumber = new Semaphore(20,20);//定义阅览室人数 public static Semaphore Pause = new Semaphore(1, 1);//控制访问时间的信号量 3.1.2 行为分析:

1) 增加读者写者:在文本框中输入进入内存时间,还有服务时间,即可创建读者写者

线程,然后直接启动即可,实现动态添加读者写者目的。

2) 外部文本读取:输入文本的名字可读取样例数据(存放在外部文件中),进行读者/ 写者、进入内存时间、读写时间的初始化。

3)时间显示功能:在主函数中点击开始按钮,就启动一个计时线程,并在主界面动态

的显示。

4) 数据显示:采用C#中DateGradeView运行过程用可视化界面动态显示,可以随时

查看阅览室中读者/写者的等待时间,状态,哪些读者写者处于等待状态。

5) 暂停继续功能:暂停继续的实现,主要是对计时线程的信号量Pause的申请和释放

实现的。 3.1.2 表示分析:

1)系统主界面设计显示读者写者的运行状态及信息,实现一些功能的按钮。

2

图 1 主界面设计

3.2 系统设计: 3.2.1 模块设计:

主框架窗口 数据录入 运行过程 动态显示 单个输入 外部文件读取 开始运行 暂停 继续 终止

图 3 系统功能模块图

数线据程 初开始始化 运

3

开始数据初始化读者类型写者人数已满是否有写着等待有读者否进入阅览室否完成工作是离开阅览室

图 4 系统主要流程图

唤醒等待的进程

3.2.2 数据结构说明:

1. 程序中的数据定义:

public static int Rcount = 0;//阅览室内读者的人数 public static int Wcount = 0;//阅览室内写者的人数

public static DataTable rwq = new DataTable();//读者等待队列 public static DataTable wwq = new DataTable();//写者等待队列

public static Label lb1, lb2;//读者写者要访问的控件设置为静态全局变量:l //b1显示 当前是读者,还是写者 //lb2显示当前阅览室的人数

public static DateTime initTime = new DateTime();//开始时系统时间 public static int uptime = 0;//系统暂停的全部时间 public static DateTime pause;//暂停时的时间 public static DateTime goon;//暂停结束的时间 2.程序中信号量的定义:

public static Semaphore Mut1 = new Semaphore(1, 1);//实现写者优先的信号量 public static Semaphore Mut2 = new Semaphore(1, 1);//访问读者数量的信号量 public static Semaphore Fmutex = new Semaphore(1, 1);//表示浏览室的信号量

public static Semaphore rNumber = new Semaphore(20,20);//定义阅览室人数 public static Semaphore Pause = new Semaphore(1, 1);//控制访问时间的信号量

4

3.2.3 算法流程图: 开始 暂停 添加读者,写者 读者线程 写者线程 继续 是 是 Form1.runTime() < IncomeTime 等待 Form1.runTime() < IncomeTime 否 否 Wcount++ Mut1.Wait() 是 Mut1.Release() Mut1.Wait() 是 Fmutex.Wait() Wcount>0 否 进行写操作 Mut2.Wait() Wcount-- Rcount++ Fmutex.Release( 是 ) Rcount==1 Mut1.Release() 否 Fmutex.Wait()

5

rNumber.WaitOne() 进行读操作 rNumber.Release() Mut2.Wait() Rcount-- Rcount == 0 Fmutex.Release() Mut2.Release() 结束

6

四、系统测试与调试分析

4.1 系统测试

测试技术:单元测试,功能测试。

单元测试是从开发者的角度来编写的,检验被测代码中的一个很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。例如可以输入正确的用户名和密码以及错误的用户名和密码来确定系统的登陆功能是否正确,如果系统能够处理不同情况的输入则说明此登陆功能没有问题。

编写单元测试有助于调用者观察、思考。特别是先写测试,迫使我们把程序设计成易于调用和可测试的,迫使我们解除软件中的耦合。编写单元测试有助于增加程序功能或者更改程序的结构,使程序变得更加完善。

功能测试是从使用者的角度来编写的,它关注系统提供的功能特征及其不同的处理条件;测试功能的不同处理流程(包括正常处理的和异常处理),它能帮助开发者更好的发心系统的不足。

测试方法:黑盒测试。

黑盒测试方法是通过使用整个软件或某种软件功能来严格地测试,而并没有通过检查程序的源代码或者很清楚地了解该软件的源代码程序具体是怎样设计的。测试人员通过输入他们的数据然后看输出的结果从而了解软件怎样工作。在测试时,把程序看作一个不能打开的黑盆子,在完全不考虑程序内部结构和内部特性的情况下,测试者在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收和正确的输出。

表 2 文本输入测试 测试说明 测试名称 采用“写优先”的策略演示“读者—写者”问题 测试目的 验证系统对于读者写者多线程的处理流程 测试技术 单元测试 测试方法 黑盒测试法 读者写者的信息输入 从界面输入信息 1,R,3,5 信息显示在table中 与预期相符 从文本中读取 rw.txt 信息显示在table中 与预期相符 输入错误信息 错误的编号 出现异常,显示失败 与预期相符 测试内容 测测试步骤 试测试数据 用预期结果 例 测试结果

表 3 读者写者测试 测试说明 测测试名称 采用“写优先”的策略演示“读者—写者”问题 测试目的 验证系统对于读者写者多线程的处理流程 测试技术 功能测试 测试方法 黑盒测试法 测试内容 在写者后面到达到的读者被阻塞 测试步骤 把数据从外部文件输入数据库,然后从哈希表中读出开始运行 1 R 1 6 2 R 2 6 7

试测试数据 3 W 3 6 用4 W 4 6 例 5 R 5 6 6 R 6 6 7 W 7 6 预期结果 {1,2} {3} {4} {5,6} {7} 测试结果 与预期相符

表 4 读者写者同时到达测试 测试说明 测试名称 采用“写优先”的策略演示“读者—写者”问题 测试目的 验证系统对于读者写者多线程的处理流程 测试技术 功能测试 测试方法 黑盒测试法 测试内容 读者写者同时到达,写者得到进入阅览室的权利 测测试步骤 试测试数据 用例 预期结果 从界面添加读者写者的信息,到达时间相同,到数据库然后开始执行 1 R 3 4 2 W 3 4 {2} {1} 测试结果 与预期相符

表 5 人数测试 测试说明 测试名称 采用“写优先”的策略演示“读者—写者”问题 测试目的 验证系统对于读者写者多线程的处理流程 测试技术 功能测试 测试方法 黑盒测试法 测试内容 采用“写优先”的策略演示“读者—写者”问题 测试步骤 从界面添加读者写者的信息,到达时间相同,到哈希表然后开始执行 测试数据 1 R 4 20 2 R 4 20 3 R 4 20 4 R 4 20 测5 R 4 20 6 R 5 20 7 R 5 20 8 R 5 20 试9 R 5 20 10 R 6 20 11 R 6 20 12 R 6 20 用13 R 6 20 14 R 6 20 15 R 5 20 16 R 5 20例 17 R 7 20 18 R 7 20 19 R 7 20 20 R 8 20 21 R 8 20 22 R 8 20 预期结果 编号1—20先执行,21,22阻塞,1-5执行完离开,21,22进入 测试结果 与预期相符

4.2 调试分析:

在开始的时候对如何将读者写者问题转化到代码非常疑惑,因为没有没有编写操作系统实验的思想,后来去网上查阅了相关的资料看了一些代码后,才有了一个初步的认识,并看了关于多线程的视频才最终确定用多线程的编写。

在整体方面,计算机的时钟是以毫秒来计算的,因此我设计了一个延迟时间Delay=1000,即以1s为一个时钟间隔。

在编写过程中遇到了一些问题花费了好多时间才解决。遇到的问题如下:

(1)开始并不知道如何处理到达时间,当其到达时该如何判断并调度它,采用的

8

是循环sleep,每次sleep(1000)一秒。

(2)如何更新运行时间与等待时间。采用timeClock(自己创建的始终线程)对时间进行记录与计算。

(3)进程状态的更新。使用state记录状态,通过申请信号量成功与否来改变状态。

(4)应该创建的线程种类。读者,写者线程,主线程,和timeClock时钟记录线程。

五、用户手册

5.1 程序开发及运行环境

本程序在Win7操作系统下利用图像界面技术设计前台界面,采用C#语言编写后台代码,文件作为后台信息的存储,在vs2010软件上开发。

Vs2010下载地址:http://www.cr173.com/soft/11547.html

5.2 具体使用步骤

1)打开vs2010软件,点击运行,系统主界面出现。 2)选择增加读者写者,出现界面如下图。

主界面显示

3) 必须先点击开始,在点击暂停,才能添加读者和写者或者直接点击文件输入,否则

出现异常

9

点击文件输入,即可从文件中读取读者写者信息,然后进行读写操作。

4)

运行信息显示界面

10

5)选择暂停,即可暂停所有线程的运行,然后动态添加读者,写者

6) 点击继续,则可将刚刚添加的读者,还有写者进行读写操作。 7)程序退出选择,点击终止,即可终止程序。

六、程序清单

6.1 外部文件

rw.txt //外部数据录入文件

6.2 主要的类

Form.cs //主界面类

Reader.cs //读者类(包含读者信息ID,进入时间,运行时间,以及读者线程调度的read方法。

Writer.cs //读者类(包含写者信息ID,进入时间,运行时间,以及写者线程调度的write方法。

6.3 本程序的源代码

using System;

using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text;

using System.Windows.Forms;

11

using System.Threading; using System.IO; /*

Semaphore的理解

通过使用一个计数器对共享资源进行访问控制,Semaphore构造器需要提供初始化的计数器(信号量)大小以及最大的计数器大小

访问共享资源时,程序首先申请一个向Semaphore申请一个许可证,Semaphore的许可证计数器相应的减一,当计数器为0时,

其他申请该信号量许可证的线程将被堵赛,直到先前已经申请到许可证的线程释放他占用的许可证让计数器加一,

这样最近去申请许可证的线程将会得到竞争得到被释放的许可证。

常见的操作方法 WaitOne():申请一个许可证 Release():释放占用的许可证 */

namespace duzhexiezhe {

public partial class Form1 : Form {

public static Semaphore Pause = new Semaphore(1, 1);//控制进程暂停访问时间的信号量

public static Semaphore Mut1 = new Semaphore(1, 1);//实现写者优先的信号量

public static Semaphore Mut2 = new Semaphore(1, 1);//访问读者数量的信号量

public static Semaphore Fmutex = new Semaphore(1, 1);//表示浏览室的信号量

public static Semaphore rNumber = new Semaphore(20,20);

public static int Rcount = 0;//阅览室内读者的人数 public static int Wcount = 0;//阅览室内写者的人数

public static DataTable rwq = new DataTable();//读者等待队列 public static DataTable wwq = new DataTable();//写者等待队列

public static Label lb1, lb2;//读者写者要访问的控件设置为静态全局变量:lb1显示 当前是读者,还是写者

//lb2显示当前阅览室的人数

public static DateTime initTime = new DateTime();//开始时系统时间 public static int uptime = 0;//系统暂停的全部时间 public static DateTime pause;//暂停时的时间

12

public static DateTime goon;//暂停结束的时间

public Form1() {

InitializeComponent(); }

private void Form1_Load(object sender, EventArgs e)//初始化一些全局控件 {

rwq.Columns.Add(\进程ID\ rwq.Columns.Add(\到达时间\ rwq.Columns.Add(\服务时间\

dgvrwq.DataSource = rwq;

wwq.Columns.Add(\进程ID\ wwq.Columns.Add(\到达时间\ wwq.Columns.Add(\服务时间\

dgvwwq.DataSource = wwq;

lb1 = label1; lb2 = label2;

}

public static int time()//开始运行到现在的时间,以秒为单位 {

TimeSpan d = DateTime.Now.Subtract(initTime); return Convert.ToInt32(d.TotalSeconds); }

public static int runTime()//程序实际运行的时间 {

Pause.WaitOne(); Pause.Release();

int t = time() - uptime; return t; }

public void timeShow()//显示时间 {

13

while (true) {

Thread.Sleep(20); Pause.WaitOne(); Pause.Release();

lbTime.Text = (time()-uptime).ToString(); } }

private void button3_Click(object sender, EventArgs e)//开始按钮点击事件

{

initTime = System.DateTime.Now;

Thread threadtime = new Thread(timeShow);

Control.CheckForIllegalCrossThreadCalls = false; threadtime.Start();

button3.Enabled = false;//开始按钮 button5.Enabled = false;//导入文件按钮 }

private void button4_Click(object sender, EventArgs e)//暂停触发的事件 {

TimeSpan d;

if (button4.Text == \暂停\暂停 {

Pause.WaitOne();

button4.Text = \继续\ pause = DateTime.Now; }

else //继续 {

Pause.Release();

button4.Text = \暂停\ goon = DateTime.Now;

d = goon.Subtract(pause);

uptime = uptime+Convert.ToInt16(d.TotalSeconds); }

14

} }

七、体会与自我评价。

此次课程设计面临的首要问题,如何将信号量用程序语言来理解,实现。一开始打算用java的swing来写,但是考虑到时间太久,已经忘的差不多了,如果在开始从头开始学的话,时间来不及,所以我决定有JSP来写,写了大概了70%,越写到后面越觉得吃力,因为那个计时器很难弄,也有客户端和服务端的及时性很难把握,所以我就考虑使用C#(选同一个课题的其它同学使用的工具,当时大家决定用C#,因为很不齿,因为这个东西用C#写太简单,想挑战自己,但是由于时间的问题,不然这个课设就不能按时完成,使用C#,我就花两天就搞定了这个课设),C#中自定义了semaphore类,所以本程序基本上代码和书上读者写者代码相同,只是加了一个信号量,还有在读者中加了一个不断检测有没有写者这几行代码来控制写者优先。

这里难度比较大的就是怎样控制写者优先,一开始用两个信号量控制,但是达不到我预期的效果,所以我采用不断检测是不是有写者的while循环,这个问题花了我一天的时间,这算是我做这个项目中比较复杂的问题了。最后还是搞定了,蛮有成就感的。

C#还有一个优势,就是它的计时器线程非常好用,正是由于这个优势使我这个课题用 C#完成的比较快。

总的来说,本项目逻辑清晰,条例顺畅,一气呵成,还是比较满意的。

八、参考文献

[1] 汤子瀛.计算机操作系统(第三版),西安电子科技大学出版社,2007.5 [2]部分算法参考百度文库。

九、课程设计评价

课 程 设 计 评 价 成绩: 教师: 年 月 日

20

本文来源:https://www.bwwdw.com/article/teoa.html

Top