操作系统原理实验报告

实验题目 二进程同步

实验二、进程同步

1.1 实验目的

  1. 现代操作系统的核心是多道程序设计、多处理器和分布式处理器,这些方案和操作系统设计技术的基础都是并发。当多个进程并发执行时,不论是在多处理器系统的情况下,还是在单处理器多道程序系统中,都会出现冲突和合作的问题。
  2. 理解操作系统中用互斥和同步解决问题。
  3. 用信号量机制分别实现读者优先和写者优先的读者-写者问题从而掌握互斥与同步的基本理念。

1.2 实验内容及要求

  1. 在Windows 环境下,创建一个控制台进程,此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面有介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者-写者问题。
  2. 读者-写者问题的读写操作限制(包括读者优先和写者优先):
  3. 1) 写-写互斥,即不能有两个写者同时进行写操作。
  4. 2) 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。
  5. 3) 读-读允许,即可以有一个或多个读者在读。
  6. 读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。
  7. 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态才能开始读操作。
  8. 运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结果读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。
  9. 测试数据文件包括n行测试数据,分别描述创建的n个线程是读者还是写者,以及读写操作的开始时间和持续时间。每行测试数据包括四个字段,各个字段间用空格分隔。第一字段为一个正整数,表示线程序号。第二字段表示相应线程角色,R表示读者,W表示写者。第三字段为一个正数,表示读写操作的开始时间:线程创建后,延迟相应时间(单位为秒)后发出对共享资源的读写申请。第四字段为一个正数,表示读写操作的持续时间。当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。

下面是一个测试数据文件的例子:

1       R       3       5

2       W       4       5

3       R       5       2

4       R       6       5

5       W       5.1     3

1.3 实验技术

  1. 在开始本实验之前,请回顾教科书的相关内容
  2. 需要做以下准备:

1.一台运行Windows 操作系统的计算机

2.计算机中需安装Visual C专业版或企业版

1.4实验步骤

(1)在Windows 环境下,创建一个控制台进程,此进程包含n个线程。用

这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面有

介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的

(2)读者-写者问题。读者-写者问题的读写操作限制(包括读者优先和写者优先):

(3)使用测试数据文件运行,分析实验结果

实验代码流程图如下:

1.5实验结果及分析说明

编译示例代码,跳出选择界面,如下图图所示:

下面是一个测试数据文件的例子:

1      R        3       5

2      W        4       5

3      R        5       2

4      R        6       5

5      W        5.1     3

将该内容写至txt文档中,修改示例代码的file为该txt文本的位置。

选择读文件优先,即输入1,运行结果如下所示:

流程:

①进程1发送读请求,并进入读文件。

②进程2发送写请求,读写互斥,所以不能进行写操作。

③进程3发送读请求,并进入读文件。

④进程5发送写请求,读写互斥,所以不能进行写操作。

⑤进程4发送读请求,并进入读文件。

⑥进程3,1,4先后完成读操作。

⑦进程2开始写操作,结束。

⑧进程5开始写操作,结束

选择写优先优先,即输入2,运行结果如下所示:

流程:

①进程1发送写请求,并进入写文件。

②进程2发送写请求,并进入写文件。

③进程3,5,4发送写请求。

④进程1结束,进程3写操作开始。

⑤进程2结束,进程5写操作开始。

⑥进程3结束,进程4写操作开始。

⑦进程5,4结束。

实验结果的分析:

将所有读者和所有写者分别存于一个读者等待队列和一个写者等待队列中,每当读允许时,就从读者队列中释放一个或多个读者线程进行读操作;每当写允许时,就从写者队列中释放一个写者进行写操作。

读者优先的情况:

读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变

量 read-count 记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当

read-count=0 时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。每一个读

者开始读文件时,必须修改 read-count 变量。因此需要一个互斥对象 mutex 来实现对全局变量 read-count 修改时的互斥。

另外,为了实现写-写互斥,需要增加一个临界区对象 write。当写者发出写请求时,必须申请临界区对象的所有权。通过这种方法,也可以实现读-写互斥,当 read-count=1 时

(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。当读者拥有临界区的所有权时,写者阻塞在临界区对象 write 上。当写者拥有临界区的所有权时,第一个读者判断完“read-count==1”后阻塞在 write 上,其余的读者由于等待对 read-count 的判断,阻塞在 mutex 上。

写者优先的情况:

写者优先与读者优先类似。不同之处在于一旦一个写者到来,它应该尽快对文件进行写操作,如果有一个写者在等待,则新到来的读者不允许进行读操作。为此应当添加一个整

型变量 write-count,用于记录正在等待的写者数目,当 write-count=0 时,才可以释放等待的读者线程队列。为了对全局变量 write-count 实现互斥,必须增加一个互斥对象 mutex3。

为了实现写者优先,应当添加一个临界区对象 read,当有写者在写文件或等待时,读

者必须阻塞在 read 上。读者线程除了要对全局变量 read-count 实现操作上的互斥外,还必须有一个互斥对象 对阻塞 read 这一过程实现互斥。这两个互斥对象分别命名为 mutex1 和 mutex2。

1.6实验体会(实验中遇到的问题及解决方法

1)实验反思

示例代码很长,阅读起来很困难,代码逻辑严谨,进一步体会到了进程同步和互斥。

2)实验收获

1.可以将所有读者和所有写者分别存于一个读者等待队列和一个写者等待队列中;每当读允许时,就从读者队列中释放一个或多个读者线程进行读操作;每当写允许时,就从写者队列中释放一个写者进行写操作。

2.了解了进程同步涉及的一些API的作用:

①CreateThread功能:创建一个线程。

②CreateMutex功能:产生一个命名的互斥量对象。

③CreateSemaphore功能:创建命名或匿名的互斥量对象。

④WaitForSingleObject功能:使程序处于等待状态,直到信号量出现或超过规定等待的最长时间,信号量大于或等于1。

⑤ReleaseSemaphore功能:将所指信号量加上指定大小的一个量,执行成功返回非0值。

⑥ReleaseMutex功能:用来打开互斥锁,即将互斥量加1,成功调用则返回0。

⑦InitializeCriticalSection功能:初始化临界区对象。

⑧EnterCriticalSection功能:等待指定临界区对象的所有权。

⑨LeaceCriticalSetion功能:释放指定临界区对象指针。

源码附录:

#include "windows.h"
#include <conio.h>
#include <stdlib.h>
#include <fstream.h>
#include <io.h>
#include <string.h>
#include <stdio.h>
#define READER 'R' // 读者
#define WRITER 'W' // 写者
#define INTE_PER_SEC 1000 // 每秒时钟中断数目。
#define MAX_THREAD_NUM 64 // 最大线程数目
#define MAX_FILE_NUM 32 // 最大数据文件数目
#define MAX_STR_LEN 32 // 字符串长度
int readcount=0; // 读者数目
int writecount=0; // 写者数目
CRITICAL_SECTION RP_Write; //临界区
CRITICAL_SECTION cs_Write;
CRITICAL_SECTION cs_Read;
struct ThreadInfo
{
int serial; // 线程序号
char entity; //线程类别(判断读者线程还是写者线程)
double delay;
double persist;
};
///
// 读者优先--读者线程
//p:读者线程信息
void RP_ReaderThread(void* p)
{
//互斥变量
HANDLE h_Mutex;
h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");
DWORD wait_for_mutex; //等待互斥变量所有权
DWORD m_delay; // 延迟时间
DWORD m_persist; // 读文件持续时间
int m_serial; //线程序号
//从参数中获得信息
m_serial=((ThreadInfo*)(p))->serial;
m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);
m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);
Sleep(m_delay); //延迟等待
printf("Reader thread %d sents the reading require.\n",m_serial);
// 等待互斥信号,保证对 readcount 的访问、修改互斥
wait_for_mutex=WaitForSingleObject(h_Mutex,-1);
//读者数目增加
readcount++;
if(readcount==1)
{//第一个读者,等待资源EnterCriticalSection(&RP_Write);
}
ReleaseMutex(h_Mutex); //释放互斥信号
//读文件
printf("Reader thread %d begins to read file.\n",m_serial);
Sleep(m_persist);
// 退出线程
printf("Reader thread %d finished reading file.\n",m_serial);
//等待互斥信号,保证对 readcount 的访问、修改互斥
wait_for_mutex=WaitForSingleObject(h_Mutex,-1);
//读者数目减少
readcount--;
if(readcount==0)
{//如果所有读者读完,唤醒写者LeaveCriticalSection(&RP_Write);
}
ReleaseMutex(h_Mutex); //释放互斥信号
}///
// 读者优先--写者线程
//p:写者线程信息
void RP_WriterThread(void* p)
{
DWORD m_delay; // 延迟时间
DWORD m_persist; // 写文件持续时间
int m_serial; //线程序号
//从参数中获得信息
m_serial=((ThreadInfo*)(p))->serial;
m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);
m_persist=(DWORD)(((ThreadInfo*)(p)) ->persist*INTE_PER_SEC);
Sleep(m_delay); //延迟等待
printf("Writer thread %d sents the writing require.\n",m_serial);
// 等待资源
EnterCriticalSection(&RP_Write);
//写文件
printf("Writer thread %d begins to Write to the file.\n",m_serial);
Sleep(m_persist);
// 退出线程
printf("Writer thread %d finished Writing to the file.\n",m_serial);
//释放资源
LeaveCriticalSection(&RP_Write);
}///
// 读者优先处理函数
//file:文件名
void ReaderPriority(char* file)
{
DWORD n_thread=0; //线程数目
DWORD thread_ID; //线程 ID
DWORD wait_for_all; //等待所有线程结束
//互斥对象
HANDLE h_Mutex;
h_Mutex=CreateMutex(NULL,FALSE,"mutex_for_readcount");
//线程对象的数组
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
readcount=0; // 初始化 readcount
InitializeCriticalSection(&RP_Write); //初始化临界区
ifstream inFile;
inFile.open("D:\\testdata.txt"); //打开文件
printf("Reader Priority:\n\n");
while(inFile)
{//读入每一个读者、写者的信息inFile>>thread_info[n_thread].serial;inFile>>thread_info[n_thread].entity;inFile>>thread_info[n_thread].delay;inFile>>thread_info[n_thread++].persist;inFile.get( );
}
for(int i=0;i< (int)(n_thread);i++)
{if(thread_info[i].entity==READER || thread_info[i].entity=='R'){h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_ReaderThread),&thread_info[i],0,&thread_ID); //创建读者线程}
else{//创建写者线程
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_WriterThread),&thread_info[i],0,&thread_ID);}
}
//等待所有线程结束
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);
printf("All reader and writer have finished operating.\n");
}
///
// 写者优先--读者线程
//p:读者线程信息
void WP_ReaderThread(void* p)
{
//互斥变量
HANDLE h_Mutex1;
h_Mutex1=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex1");
HANDLE h_Mutex2;
h_Mutex2=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex2");
DWORD wait_for_mutex1; //等待互斥变量所有权
DWORD wait_for_mutex2;
DWORD m_delay; // 延迟时间
DWORD m_persist; // 读文件持续时间
int m_serial; //线程序号
//从参数中获得信息
m_serial=((ThreadInfo*)(p))->serial;
m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);
m_persist=(DWORD)(((ThreadInfo*)(p)) ->persist*INTE_PER_SEC);
Sleep(m_delay); //延迟等待
printf("Reader thread %d sents the reading require.\n",m_serial);
wait_for_mutex1= WaitForSingleObject(h_Mutex1,-1);
//进入读者临界区EnterCriticalSection(&cs_Read);
// 阻塞互斥对象 mutex2,保证对 readcount 的访问、修改互斥
wait_for_mutex2= WaitForSingleObject(h_Mutex2,-1);
//修改读者数目
readcount++;
if(readcount==1)
{//如果是第一个读者,等待写者写完EnterCriticalSection(&cs_Write);
}
ReleaseMutex(h_Mutex2); //释放互斥信号 mutex2
// 让其他读者进入临界区
LeaveCriticalSection(&cs_Write);
ReleaseMutex(h_Mutex1);
//读文件
printf("Reader thread %d begins to read file.\n",m_serial);
Sleep(m_persist);
// 退出线程
printf("Reader thread %d finished reading file.\n",m_serial);
// 阻塞互斥对象 mutex2,保证对 readcount 的访问、修改互斥
wait_for_mutex2= WaitForSingleObject(h_Mutex2,-1);
readcount--;
if(readcount==0)
{// 最后一个读者,唤醒写者LeaveCriticalSection(&cs_Write);
}
ReleaseMutex(h_Mutex2); //释放互斥信号
}
///
// 写者优先--写者线程
//p:写者线程信息
void WP_WriterThread(void* p)
{
DWORD m_delay; // 延迟时间
DWORD m_persist; // 写文件持续时间
int m_serial; //线程序号
DWORD wait_for_mutex3;
//互斥对象
HANDLE h_Mutex3;
h_Mutex3= OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex3");
//从参数中获得信息
m_serial=((ThreadInfo*)(p))->serial;
m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);
m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);
Sleep(m_delay); //延迟等待
printf("Writer thread %d sents the writing require.\n",m_serial);
// 阻塞互斥对象 mutex3,保证对 writecount 的访问、修改互斥
wait_for_mutex3= WaitForSingleObject(h_Mutex3,-1);
writecount++; //修改读者数目
if(writecount==1)
{//第一个写者,等待读者读完EnterCriticalSection(&cs_Read);
}
ReleaseMutex(h_Mutex3);
//进入写者临界区
EnterCriticalSection(&cs_Write);
//写文件
printf("Writer thread %d begins to Write to the file.\n",m_serial);
Sleep(m_persist);
// 退出线程
printf("Writer thread %d finishing Writing to the file.\n",m_serial);
//离开临界区
LeaveCriticalSection(&cs_Write);
// 阻塞互斥对象 mutex3,保证对 writecount 的访问、修改互斥
wait_for_mutex3= WaitForSingleObject(h_Mutex3,-1);
writecount--; //修改读者数目
if(writecount==0)
{//写者写完,读者可以读LeaveCriticalSection(&cs_Read);
}
ReleaseMutex(h_Mutex3);
}
///
// 写者优先处理函数
//file:文件名
void WriterPriority(char* file)
{
DWORD n_thread=0; //线程数目
DWORD thread_ID; //线程 ID
DWORD wait_for_all; //等待所有线程结束
//互斥对象
HANDLE h_Mutex1;
h_Mutex1=CreateMutex(NULL,FALSE,"mutex1");
HANDLE h_Mutex2;
h_Mutex2=CreateMutex(NULL,FALSE,"mutex2");
HANDLE h_Mutex3;
h_Mutex3=CreateMutex(NULL,FALSE,"mutex3");
//线程对象
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
readcount=0; // 初始化 readcount
writecount=0; // 初始化 writecount
InitializeCriticalSection(&cs_Write); //初始化临界区
InitializeCriticalSection(&cs_Read);
ifstream inFile;
inFile.open("D:\\testdata.txt"); //打开文件
printf("Writer Priority:\n\n");
while(inFile)
{//读入每一个读者、写者的信息inFile>>thread_info[n_thread].serial;inFile>>thread_info[n_thread].entity;inFile>>thread_info[n_thread].delay;inFile>>thread_info[n_thread++].persist;inFile.get( );
}
for(int i=0;i< (int)(n_thread);i++)
{if (thread_info[i].entity==READER || thread_info[i].entity=='R'){//创建读者线程h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_WriterThread),&thread_info[i],0,&thread_ID);}
else{//创建写者线程
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WP_WriterThread),&thread_info[i],0,&thread_ID);}
}
//等待所有线程结束
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);
printf("All reader and writer have finished operating.\n");
}
///
//主函数
int main(int argc,char* argv[])
{
char ch;
while (true)
{//打印提示信息printf("************************************************\n");printf(" 1:Reader Priority\n");printf(" 2:Writer Priority\n");printf(" 3:Exit Priority\n");printf("************************************************\n");printf("Enter your choice(1,2 or 3): ");//如果输入信息不正确,继续输入do{ch=(char)_getch( );}while(ch != '1' &&ch != '2' && ch != '3');system("cls");//选择 3,返回if(ch=='3')return 0;//选择 1,读者优先else if(ch=='1')ReaderPriority("thread.dat");//选择 2,写者优先else if(ch=='2')WriterPriority("thread.dat");//结束printf("\nPress Any Key To Continue: ");_getch( );system("cls");
}
return 0;
}

操作系统原理实验-进程同步相关推荐

  1. ZUCC_操作系统原理实验_实验九 消息队列

    操作系统原理实验报告 课程名称 操作系统原理实验 实验项目名称 实验九 消息队列 实验目的 了解 Linux 系统的进程间通信机构 (IPC): 理解Linux 关于消息队列的概念: 掌握 Linux ...

  2. ZUCC_操作系统原理实验_Lab9进程的通信消息队列

    lab9进程的通信–消息队列 一.两个进程并发执行,通过消息队列,分别进行消息的发送和接收 1.代码: //接受消息 #include<stdio.h> #include<stdli ...

  3. 操作系统原理 实验1、2

    操作系统原理 实验1.2 1.高响应比作业调度 代码示例 #include<malloc.h> #include<stdio.h> #include<string.h&g ...

  4. 操作系统原理实验二(三)

    继续完成操作系统原理的实验 4.5(实验目的:熟悉Window线程创建过程)在windows环境下,利用高级语言编程环境(限定为VS环境或VC环境)调用CreateThread函数实现"并发 ...

  5. 操作系统原理实验(3):操作系统的基石中断与异常

    一.实验目的 中断.异常和陷阱指令(合称类中断)是操作系统的基石,现代操作系统就是由(类)中断驱动的.本实验的目的在于深刻理解(类)中断的原理和机制,掌握 CPU 访问设备控制器的方法,掌握 x86 ...

  6. 操作系统原理实验(5):内存管理

    一.实验目的 分页内存管理是内存管理的基本方法之一.本实验的目的在于全面理解分页式内存管理的基本方法以及访问页表,完成地址转换等的方法. 二.实验过程&错误 内容(一):设计不同的方式引发页错 ...

  7. ZUCC 操作系统原理实验 模拟考试

    由ZUCC INTERSECTION题库提供答案. 判断题 1.当同时需要用两个互斥信号量时,总是让它们以交错的顺序加锁,以避免死锁. 编号 选项 A T B F 2.由signal()注册的信号只是 ...

  8. 操作系统原理实验(四)深渊:竞争条件与死锁(硬件中断)

    硬件中断 中断控制器 启动中断 处理定时器中断 死锁 竞争条件 HLT指令 键盘输入 中断控制器 中断提供了一种从附加硬件设备通知CPU的方法.这个英特尔8259是1976年推出的可编程中断控制器(P ...

  9. 模拟进程创建、终止、阻塞、唤醒原语(操作系统原理实验)

    0

最新文章

  1. 使用Windows命令行启动服务
  2. python填写excel内容_python实现数据写入excel表格
  3. map和list遍历基础
  4. KMP算法中next数组的理解与算法的实现(java语言)
  5. python组合数据分类_Python 数据可视化:分类特征统计图
  6. CF196E Opening Portals
  7. 搜索了一下电脑上编程相关的 pdf, 看有你需要的吗?
  8. 多文件上传组件FineUploader使用心得
  9. php error_log记录日志的使用方法和配置
  10. 如何删除本地mysql的数据库_如何完全卸载 mysql 数据库
  11. 波形和函数发生器(Waveform and Function Generator)
  12. java求指数_Java Math类的常用方法,指数运算
  13. 三月写给沉默王二的一封道歉信
  14. 8位并行左移串行转换电路_单片机试题
  15. 为河南小伙恩辉舍己救人点赞<原创>
  16. Typora+PciGo-Core+SMMS自动上传图片
  17. ElasticSearch学习笔记(八)Java AP实现增删改查
  18. python 清空表格_python 清空表数据库表
  19. git视频及对初学者的学习建议 转自亨利的3D幻想世界
  20. jsp中EL表达式显示时中文乱码

热门文章

  1. 关于GPS 转换实用地图算法
  2. python自动化和教程_python自动化基本技术原理
  3. ORBSLAM3的IMU积分求解过程
  4. springboot高校社团管理系统
  5. RGB 空间颜色量化 - 减少颜色数目
  6. 28人买可乐喝,3个可乐瓶盖可以换一瓶可乐,那么要买多少瓶可乐,够28人喝?假如是50人,又需要买多少瓶可乐?(解读误区)
  7. 2022起重机司机(限桥式起重机)上岗证题目及在线模拟考试
  8. python 获取国内期货_获取和讯期货数据(Python版本).md
  9. GitHub标星10.8K!快速搭建私人网盘
  10. TableRow设置高度