前言
课程设计开始了,实验很有意思,写博客总结学到的知识
白嫖容易,创作不易,学到东西才是真
本文原创,创作不易,转载请注明!!!
本文链接
个人博客:https://ronglin.fun/archives/183
PDF链接:见博客网站
CSDN: https://blog.csdn/RongLin02/article/details/118309933
为了美观,实验源代码在结尾处,整合版见下
链接:https://pan.baidu/s/1rXj1QJGuw-BVc5sQWret9w
提取码:Lin2
本次操作系统课程设计合集
操作系统课程设计源代码
本次操作系统课程设计合集
操作系统课设之Windows 进程管理
操作系统课设之Linux 进程管理
操作系统课设之Linux 进程间通信
操作系统课设之Windows 的互斥与同步
操作系统课设之内存管理
操作系统课设之虚拟内存页面置换算法的模拟与实现
操作系统课设之基于信号量机制的并发程序设计
操作系统课设之简单 shell 命令行解释器的设计与实现
仅用于学习,如有侵权,请联系我删除
实验题目
基于信号量机制的并发程序设计
实验目的
(1) 回顾操作系统进程、线程的有关概念,针对经典的同步、互斥、死锁与饥饿问题进行并发程序设计与实现。
(2) 理解互斥体对象,利用互斥与同步操作编写读者-写者问题的并发程序,加深对 P (即semWait)、V(即 semSignal)原语以及利用 P、V 原语进行进程间同步与互斥操作的理解。
(3) 理解 Linux 支持的信息量机制,利用 IPC 的信号量系统调用编程实现哲学家进餐问题。
总体设计
因为指导书上只写了完成其一即可,我选择的题目是在Windows下实现读者写者问题。
背景知识:
主要是熟悉Windows API,熟悉PV操作对应的语法结构
HANDLE WriteSemaphore; //定义信号量
WriteSemaphore = CreateSemaphore(NULL,1,MAX_READER_NUM,NULL);//信号量初始化
DWORD WINAPI reader(LPVOID); //定义线程的执行函数
DWORD readerID[READER_NUM]; //读者线程的标识符
CreateThread(NULL,0,reader,NULL,0,&readerID[i]); //启动线程
//PV操作
WaitForSingleObject(XSemaphore,INFINITE); //semWait(x);
ReleaseSemaphore(XSemaphore,1,NULL); //semSignal(x);
还有就是对读者写者问题的理解,由于书上已经说的很详尽,而且还给了伪代码,这里只是浅谈一下。
读者写者问题:
存在一个多进程共享的数据区,该数据区可以是一个文件或一块内存空间,甚至可以是一组寄存器,有些进程(reader)只读取这个数据区中的数据,有些进程(writer)只往数据区中写数据。,此外,还必须满足:
1.任意数量的读进程可同时读这个文件。
2.一次只有一个写进程可以写文件
3.若写进程正在写文件,则禁止任何读进程读文件。
书上实现的读者优先的算法思路是:
写进程比较简单,信号量WriteSemaphore用于实施排斥,只要一个写进程正在访问数据区,其他写进程和读进程就都不能访问它。读进程也使用WriteSemaphore实施互斥,但为了允许多个读进程,没有读进程正在读时,第一个试图读的读进程需要在WriteSemaphore上等待。当至少已有一个读进程在读时,随后的读进程无须等待,可以直接进入。readcount用于记录读进程的数量,信号量XSemaphore用于确保readcount被正确地更新。
详细设计
主要是调用Windows的API
首先就是宏定义
#define MAX_READER_NUM 512 //最大读者数
#define READER_NUM 3 //读者数量
#define WRITER_NUM 2 //写者数量
#define MOD 100 //一个模数
解释一下模数的意义,为了测试读者写者的实际效果,我定义了一个test变量,当写者写的时候test自增1,为了防止自增次数太多导致数据溢出,就定义了一个模数,读者就负责读test数据。
读者线程执行:
void READUNIT()
{
cout<<"一个读者开始阅读:";
cout<<test<<endl;
}
写者线程写:
void WRITEUNIT()
{
cout<<"写者开始写:";
test = (test+1) % MOD;
cout<<test<<endl;
}
这两个是读者写者执行的主要逻辑功能
然后就是读者线程的执行函数:
DWORD WINAPI reader(LPVOID lpPara)
{
while(p_ccontinue)
{
WaitForSingleObject(XSemaphore,INFINITE); //semWait(x);
readcount++;
if(readcount == 1) //第一个读者来了
WaitForSingleObject(WriteSemaphore,INFINITE); //semWait(wsem);
ReleaseSemaphore(XSemaphore,1,NULL); //semSignal(x);
READUNIT();
//阅读完毕
WaitForSingleObject(XSemaphore,INFINITE); //semWait(x);
readcount--;
//无读者,释放资源
if(readcount == 0)
ReleaseSemaphore(WriteSemaphore,1,NULL); //semSignal(wsem);
ReleaseSemaphore(XSemaphore,1,NULL); //semSignal(x);
Sleep(3000);
}
return 0;
}
写者线程的执行函数
DWORD WINAPI writer(LPVOID lpPara)
{
while(p_ccontinue)
{
WaitForSingleObject(WriteSemaphore,INFINITE); //semWait(wsem);
WRITEUNIT();
ReleaseSemaphore(WriteSemaphore,1,NULL); //semSignal(wsem);
Sleep(2000);
}
return 0;
}
实验结果与分析
结果如上,是符合预期的,读者只读test变量的数据,而写者对test变量自增。
小结与心得体会
本实验的难度不大,主要是熟悉Windows API用法,了解信号量的定义和初始化,线程的创建和PV操作,然后就是理解课本上对于读者写者问题的讲解。=w=
源代码
#include <windows.h>
#include <iostream>
#define MAX_READER_NUM 512
#define READER_NUM 3
#define WRITER_NUM 2
#define MOD 100
using namespace std;
int readcount = 0;
HANDLE WriteSemaphore; //实现读写互斥
HANDLE XSemaphore; //对于人数修改的互斥量
DWORD WINAPI reader(LPVOID); //读者线程
DWORD WINAPI writer(LPVOID); //写者线程
bool p_ccontinue = true; //控制程序结束
int test = 0;
int main()
{
//初始化两个信号量
/*结构体指针;信号量对象的初始计数;信号量对象的最大计数;信号量对象的名称*/
WriteSemaphore = CreateSemaphore(NULL,1,MAX_READER_NUM,NULL);
XSemaphore = CreateSemaphore(NULL,1,MAX_READER_NUM,NULL);
//用WindowsAPI模拟课本上 parbegin(reader,writer);
//总的线程数
HANDLE hThreads[READER_NUM + WRITER_NUM]; //各线程的 handle
DWORD readerID[READER_NUM]; //读者线程的标识符
DWORD writerID[WRITER_NUM]; //写者线程的标识符
//创建读者线程
for (int i=0; i<READER_NUM; i++)
{
hThreads[i]=CreateThread(NULL,0,reader,NULL,0,&readerID[i]);
if (hThreads[i]==NULL)
return -1;
}
//创建写者线程
for (int i=0; i<WRITER_NUM; i++)
{
hThreads[READER_NUM+i]=CreateThread(NULL,0,writer,NULL,0,&writerID[i]);
if (hThreads[i]==NULL)
return -1;
}
while(p_ccontinue)
{
if(getchar()) //按回车后终止程序运行
{
p_ccontinue = false;
}
}
return 0;
}
//读者阅读
void READUNIT()
{
cout<<"一个读者开始阅读:";
cout<<test<<endl;
}
//写者写
void WRITEUNIT()
{
cout<<"写者开始写:";
test = (test+1) % MOD;
cout<<test<<endl;
}
//读者
DWORD WINAPI reader(LPVOID lpPara)
{
while(p_ccontinue)
{
WaitForSingleObject(XSemaphore,INFINITE); //semWait(x);
readcount++;
if(readcount == 1) //第一个读者来了
WaitForSingleObject(WriteSemaphore,INFINITE); //semWait(wsem);
ReleaseSemaphore(XSemaphore,1,NULL); //semSignal(x);
READUNIT();
//阅读完毕
WaitForSingleObject(XSemaphore,INFINITE); //semWait(x);
readcount--;
//无读者,释放资源
if(readcount == 0)
ReleaseSemaphore(WriteSemaphore,1,NULL); //semSignal(wsem);
ReleaseSemaphore(XSemaphore,1,NULL); //semSignal(x);
Sleep(3000);
}
return 0;
}
//写者
DWORD WINAPI writer(LPVOID lpPara)
{
while(p_ccontinue)
{
WaitForSingleObject(WriteSemaphore,INFINITE); //semWait(wsem);
WRITEUNIT();
ReleaseSemaphore(WriteSemaphore,1,NULL); //semSignal(wsem);
Sleep(2000);
}
return 0;
}