最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

操作系统课设之基于信号量机制的并发程序设计

运维笔记admin21浏览0评论

前言

课程设计开始了,实验很有意思,写博客总结学到的知识
白嫖容易,创作不易,学到东西才是真
本文原创,创作不易,转载请注明!!!
本文链接
个人博客: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;
}

发布评论

评论列表(0)

  1. 暂无评论