操作系统课程设计报告lxx

更新时间:2023-10-14 18:02:01 阅读量: 综合文库 文档下载

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

江苏大学

《操作系统》课程设计说明书

设计题目 进程通信与进程同步机制实践 学生姓名

指导老师 薛安荣 学 院 计算机学院 专业班级 软件工程1202班 学号

完成时间 2015年1月2日

一. 课程设计题目

某银行提供5个服务窗口(3个对私服务窗口,1个对公服务窗口,1个理财服务窗口)和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号;若没有空座位,则在门外等待或离开。取号机每次仅允许一位顾客使用,有对公、对私和理财三类号,每位顾客只能选取其中一个。当营业员空闲时,通过叫号选取一位顾客,并为其服务。请用P、V操作写出进程的同步算法。

(1)可限定最大服务人数

(2)办理对私、对公、理财业务随机,可通过随机数产生。 (3)取号时顾客拿到的号含有号码和显示当前等待人数,例如A、B、C分别代表对私、对公、理财,“号码:A5”表示取的是对私服务号,编号是5。

二.课程设计目的

1、掌握基本的同步与互斥算法,理解银行排队系统操作模型。 2、学习使用Windows7中基本的同步对象,掌握相关API的使用方法。

3、了解Windows7中多线程的并发执行机制,实现进程的同步与互斥。

三.课程设计要求

◆学习并理解生产者/消费者模型及其同步/互斥规则;

◆学习了解Windows同步对象及其特性; ◆熟悉实验环境,掌握相关API的使用方法;

◆设计程序,实现生产者/消费者进程(线程)的同步与互斥; ◆提交实验报告。

四.需要了解的知识

1.同步对象

同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。本实验中使用到信号量、互斥量和临界区三个同步对象。

2.同步对象的使用步骤:

◆创建/初始化同步对象。

◆请求同步对象,进入临界区(互斥量上锁)。 ◆释放同步对象(互斥量解锁)。

五.需要用到的API函数及相关函数

我们利用Windows SDK提供的API编程实现实验题目要求,而VC中包含有Windows SDK的所有工具和定义。要使用这些API,需要包含堆这些函数进行说明的SDK头文件——最常见的是Windows.h(特殊的API调用还需要包含其他头文件)。

本实验使用到的API的功能和使用方法简单介绍 1、WaitForSingleObject(cs1,INFINITE); ? WaitForSingleObject(seat,INFINITE);

? WaitForSingleObject(mutex,INFINITE);

? 功能——对请求服务顾客,座位和互斥量信号量进行P操作 ? 格式

DWORD WINAPI WaitForSingleObject(

_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds ); ? 参数说明

hHandle——信号量指针。

dwMilliseconds——等待的最长时间(INFINITE为无限等待)。 2、ReleaseMutex( mutex );

? 功能——打开互斥锁,即把互斥量加1。成功调用则返回0 ? 格式

BOOL WINAPI ReleaseMutex(

_In_ HANDLE hMutex); ? 参数说明 hMutex——互斥量

3. ReleaseSemaphore(s3,1,NULL); ReleaseSemaphore(cs1,1,NULL); ReleaseSemaphore(seat,1,NULL);

? 功能——对窗口,顾客,座位信号量进行V操作 ? 格式

BOOL WINAPI ReleaseSemaphore(

_In_ HANDLE hSemaphore, _In_ LONG lReleaseCount, _Out_opt_ LPLONG lpPreviousCount ); ? 参数说明

hSemaphore——信号量指针。 lReleaseCount——信号量的增量。 lppreviousCount——保存信号量当前值。

4、CreateThread(NULL,0,consumer1,NULL,0,NULL); ? 功能——创建一个在调用进程的地址空间中执行的线程 ? 格式

HANDLE WINAPI CreateThread(

_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize,

_In_ LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ __drv_aliasesMem LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_opt_ LPDWORD lpThreadId); ? 参数说明

lpThreadAttributes——指向一个LPSECURITY_ATTRIBUTES(新线程的安全性描述符)。

dwStackSize——定义原始堆栈大小。

lpStartAddress——指向使用LPTHRAED_START_ROUTINE类型

定义的函数。

lpParamiter——定义一个给进程传递参数的指针。 dwCreationFlags——定义控制线程创建的附加标志。 lpThread——保存线程标志符(32位)

5、mutex = CreateMutex(NULL,FALSE,NULL); ? 功能——创建一个命名或匿名的互斥量对象 ? 格式

HANDLE WINAPI CreateMutexW(

_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, _In_ BOOL bInitialOwner,

_In_opt_ LPCWSTR lpName); ? 参数说明

lpMutexAttributes——必须取值NULL。

bInitialOwner——指示当前线程是否马上拥有该互斥量(即马上加锁)。

lpName——互斥量名称。

5. seat = CreateSemaphore(NULL,Seat , Seat, NULL); ? 功能——创建一个命名或匿名的信号量对象 ? 格式

HANDLE WINAPI CreateSemaphoreW(

_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, _In_ LONG lInitialCount,

_In_ LONG lMaximumCount, _In_opt_ LPCWSTR lpName); ? 参数说明

lpSemaphoreAttributes——必须取值NULL。

lInitialCount——信号量的初始值。该值大于0,但小于lMaximumCount指定的最大值。 lpName——信号量名称。

六.原理及算法

1、信号量设置

seat:座位信号量 s1:对私服务窗口的信号量 s2:对公服务窗口的信号量 s3:理财服务窗口的信号量

cs1:请求对私服务窗口的客户的信号量 cs2:请求对公服务窗口的客户的信号量 Cs3:请求理财服务窗口的客户的信号量 mutex:取号机互斥信号量

c1[Customer_num]:请求对私服务顾客线程信号量 c2[Customer_num]:请求对公服务顾客线程信号量 c3[Customer_num]:请求理财服务顾客线程信号量

ss1[StaticServer]:窗口对私服务信号量 ss2[PublicServer]:窗口对公服务信号量 ss3[FinancialService]:窗口理财服务信号量

2、线程创建

StaticServer 3:3个对私窗口线程 PublicServer 1:1个对私窗口线程 FinancialService 1:1个理财窗口线程 consumer1:对私顾客线程 consumer2:对公顾客线程 Consumer3:理财顾客线程 server1:窗口对私线程 Server2:窗口对公线程 Server3:窗口理财线程

3、P、V操作

DWORD WINAPI server1(PVOID s1pv) //窗口对私线程代码 {

while(true) {

WaitForSingleObject(cs1,INFINITE);//p(&cs1)对私顾客-1 Sleep(ServeTime);//运行一个窗口服务时间

EnterCriticalSection(&x);//进入临界区,窗口不允许其他

顾客进入

cout<<\对私窗口叫号!\<

LeaveCriticalSection(&x);//离开临界区

ReleaseSemaphore(s1,1,NULL);//v(&s1)释放对私窗口+1 EnterCriticalSection(&c_seat);//进入临界区,座位不共享 seat_num++;//可用座位+1

LeaveCriticalSection(&c_seat);离开临界区 } return 0;

}

Server2//营业员对公窗口线程代码相似 Server3//营业员理财窗口线程代码相似

/*******************取号同一时间最多一个******************/

WaitForSingleObject(mutex,INFINITE);//p(&mutex)互斥量

P操作

EnterCriticalSection(&x);//进入临界区

cout<<\顾客\<

ReleaseSemaphore(cs1,1,NULL);//v(&cs1)释放1对私顾客

七.

算法流程图

八.

开始 客户到达 是 座位满? 离开? 是 离开 否 否 门口等待 是 服务人数满? 否 排队取号 是 否 窗口闲置?

服务并离开 结束

八.主要数据结构及实现

通过创建8个线程来实现银行排队系统,3个对私窗口,1个对公窗口,1个理财窗口,1个对私等待顾客,1个对公等待顾客, 1个理财等待顾客。8个窗口建立之后,来顾客就执行,没顾客就挂起,进入等待状态,通过设计一个随机数来实现五分之三的几率进行对私服务,五分之一的几率进行对公服务,五分之一的几率进行理财服务,服务时间固定,取号机只能一个人用,所以设置了mutex互斥信号量。门口来人时,先检查座位是否满了,没满,则取号,进入等待室,然后等待窗口叫号,当服务完时,离开并释放一个座位。若座位满了,设置了伪随机数实现二分之一的几率选择留下等待或离开。

窗口线程创建过程:(窗口线程分对公顾客线程、对私顾客线程和理财顾客线程,创建过程基本类似,下面列举对私顾客线程创建过程)

DWORD WINAPI server1(PVOID s1pv) //窗口对私线程代码 {

while(true) {

WaitForSingleObject(cs1,INFINITE);//p(&cs1)对私顾客-1 Sleep(ServeTime);//运行一个窗口服务时间

EnterCriticalSection(&x);//进入临界区,窗口不允许其他顾客进入 cout<<\对私窗口叫号!\<

LeaveCriticalSection(&x);//离开临界区

ReleaseSemaphore(s1,1,NULL);//v(&s1)释放对私窗口+1 EnterCriticalSection(&c_seat);//进入临界区,座位不共享

}

}

seat_num++;//可用座位+1

LeaveCriticalSection(&c_seat);离开临界区

return 0;

顾客线程创建过程:(窗口线程分3个对私窗口、1个对公窗口和1个理财窗口,创建过程基本类似,下面列举对公窗口1线程创建过程)

DWORD WINAPI consumer1(PVOID c1pv)//顾客对私线程代码 {

cout<<\这是第\<

srand((unsigned)time(0));//伪随机数 int n=rand()%2; { //离开 }

else if(seat_num<=0) { //留下等待 }

EnterCriticalSection(&c_seat); seat_num--;//可用座位数-1 LeaveCriticalSection(&c_seat);

//WaitForSingleObject(seat,INFINITE);//p(&seat)

WaitForSingleObject(mutex,INFINITE);//p(&mutex) 取号在临界区操作 EnterCriticalSection(&nu1);

number1++; //对私服务的顾客取号得到的编号+1 LeaveCriticalSection(&nu1); //EnterCriticalSection(&y); number++;//服务人数+1 //LeaveCriticalSection(&y); m1++;//取号时显示当前等待人数+1 int temp1=number1;

EnterCriticalSection(&coun); amount ++;//门外等待人数+1 LeaveCriticalSection(&coun); EnterCriticalSection(&x);

cout<<\该顾客在门外等待,已有\<

cout<<\座位已满,该顾客离开!\<

if(seat_num<=0&&n==1)

Sleep(ServeTime);//服务完一个顾客 m1--;//当前等待人数—1

ReleaseSemaphore(seat,1,NULL);//v(&seat) EnterCriticalSection(&c_seat); seat_num++;//可用座位+1 LeaveCriticalSection(&c_seat); if(seat_num<=0)//判断座位是否够 { }

EnterCriticalSection(&x);

cout<<\顾客A\<

EnterCriticalSection(&x);

cout<<\门外还剩\<

EnterCriticalSection(&x);

cout<<\顾客\<<\<

Sleep(ServeTime);//休眠一段时间

WaitForSingleObject(s1,INFINITE);//p(&s1)

EnterCriticalSection(&x);

cout<<\顾客A\<

ReleaseMutex(mutex);//v(&mutex)

ReleaseSemaphore(cs1,1,NULL);//v(&cs1) 释放一个对私窗口

EnterCriticalSection(&x);

cout<<\顾客\<

私服务\<

}

九.实验测试结果及结果分析

结果分析

顾客进入银行之前,首先判断是否有空座位,若有,则在取号机上取号,等待窗口服务,若没有随机选择去留。对于窗口而言,只要其空闲,则按照顾客取号的顺序为顾客提供服务。所有线程执行结束之后程序结束。

十.课程设计总结

通过此次课程设计,使我更加充分的掌握了有关操作系PV操作,在设计过程中虽然遇到了一些问题,但经过一次又一次的思考,一遍又一遍的检查终于找出了原因所在,也暴露出了前期我在这方面的知识欠缺和经验不足。在课程设计过程中,我们不断发现错误,不断改正,不断领悟,本身就是在践行“过而能改,善莫大焉”的知行观。这次课程设计终于顺利完成了,在设计中遇到了很多问题,最后在老师和同学的指导下,终于游逆而解。在这学期的实验中,不仅培养了独立思考、动手操作的能力,在各种其它能力上也都有了提高。更重要的是,在实验课上,我们学会了很多学习的方法。而这是日后最实用的,真的是受益匪浅。要面对社会的挑战,只有不断的学习、实践,再学习、再实践。这对于我们的将来也有很大的帮助。以后,不管有多苦,我想我们都能变苦为乐,找寻有趣的事情,发现其中珍贵的事情。就像中国提倡的艰苦奋斗一样,我们都可以在实验结束之后变的更加成熟,会面对需要面对的事情。

十一.源程序清单

主要代码

#include\ #include \ #include using namespace std; #define StaticServer 3

//私有服务

#define PublicServer 1 //公有服务 #define FinancialService 1 //理财服务 #define Seat 10

//座位量

#define ServeTime 2000

//服务时间 //顾客数量

//顾客来的最大间隔时间

#define Customer_num 50 #define Customer_time 500

//取号号码 int number = 0; int number1 = 0,m1=0; int number2 = 0,m2=0; int number3 = 0,m3=0; int seat_num=10; int amount =0; //创建句柄

HANDLE seat,s1,s2,s3,cs1,cs2,cs3; HANDLE mutex; HANDLE

c1[Customer_num],c2[Customer_num],c3[Customer_num],ss1[StaticServer],ss2[PublicServer],ss3[FinancialService]; CRITICAL_SECTION c_seat; CRITICAL_SECTION x; CRITICAL_SECTION coun; CRITICAL_SECTION nu1; CRITICAL_SECTION nu2; CRITICAL_SECTION nu3;

DWORD WINAPI server1(PVOID s1pv) //窗口对私线程代码 { }

DWORD WINAPI server2(PVOID s2pv) //窗口对公线程代码 {

while(true) {

WaitForSingleObject(cs2,INFINITE);//p(&cs2) Sleep(ServeTime);

EnterCriticalSection(&x); cout<<\对公窗口叫号!\<

WaitForSingleObject(cs1,INFINITE);//p(&cs1) Sleep(ServeTime);

EnterCriticalSection(&x); cout<<\对私窗口叫号!\<

ReleaseSemaphore(s1,1,NULL);//v(&s1) EnterCriticalSection(&c_seat); seat_num++;

LeaveCriticalSection(&c_seat);

//临界区,防止重叠

//互斥量

//座位数,对私服务窗口,对公服务窗口,对理财服务

窗口,进行对私服务顾客,进行对公服务顾客,进行对理财服务顾客

}

}

LeaveCriticalSection(&x);

ReleaseSemaphore(s2,1,NULL);//v(&s2) EnterCriticalSection(&c_seat); seat_num++;

LeaveCriticalSection(&c_seat);

return 0;

DWORD WINAPI server3(PVOID s3pv) //窗口对理财线程代码 { }

DWORD WINAPI consumer1(PVOID c1pv)//顾客对私线程代码 {

cout<<\这是第\<

srand((unsigned)time(0)); int n=rand()%2; { }

else if(seat_num<=0) { }

EnterCriticalSection(&coun); amount ++;

LeaveCriticalSection(&coun); EnterCriticalSection(&x);

cout<<\该顾客在门外等待,已有\<

cout<<\座位已满,该顾客离开!\<

while(true) { } return 0;

WaitForSingleObject(cs3,INFINITE);//p(&cs3) Sleep(ServeTime);

EnterCriticalSection(&x); cout<<\对理财窗口叫号!\<

ReleaseSemaphore(s3,1,NULL);//v(&s3) EnterCriticalSection(&c_seat); seat_num++;

LeaveCriticalSection(&c_seat);

if(seat_num<=0&&n==1)

EnterCriticalSection(&c_seat); seat_num--;

LeaveCriticalSection(&c_seat);

//WaitForSingleObject(seat,INFINITE);//p(&seat) WaitForSingleObject(mutex,INFINITE);//p(&mutex) EnterCriticalSection(&nu1); number1++;

LeaveCriticalSection(&nu1); //EnterCriticalSection(&y); number++;

//LeaveCriticalSection(&y); m1++;

int temp1=number1; EnterCriticalSection(&x);

cout<<\顾客\<

cout<<\顾客A\<

WaitForSingleObject(s1,INFINITE);//p(&s1) EnterCriticalSection(&x);

cout<<\顾客\<<\<

ReleaseSemaphore(seat,1,NULL);//v(&seat) EnterCriticalSection(&c_seat); seat_num++;

LeaveCriticalSection(&c_seat); if(seat_num<=0) {

EnterCriticalSection(&x);

cout<<\门外还剩\<

私服务\<

}

}

EnterCriticalSection(&x);

cout<<\顾客A\<

DWORD WINAPI consumer2(PVOID c2pv)//顾客对公线程代码 {

EnterCriticalSection(&x);

cout<<\顾客\<

//WaitForSingleObject(seat,INFINITE);//p(&seat) WaitForSingleObject(mutex,INFINITE);//p(&mutex) EnterCriticalSection(&nu2); number2++;

LeaveCriticalSection(&nu2); //EnterCriticalSection(&y); number++;

//LeaveCriticalSection(&y); m2++;

int temp2=number2;

cout<<\这是第\<

srand((unsigned)time(0)); int n=rand()%2; if( seat_num<=0&&n==1) { }

else if(seat_num<=0) { }

EnterCriticalSection(&c_seat); seat_num--;

LeaveCriticalSection(&c_seat);

EnterCriticalSection(&coun); amount ++;

LeaveCriticalSection(&coun); EnterCriticalSection(&x);

cout<<\该顾客在门外等待,已有\<

cout<<\座位已满,该顾客离开!\<

公服务\<

}

LeaveCriticalSection(&x); ReleaseMutex(mutex);//v(&mutex) ReleaseSemaphore(cs2,1,NULL);//v(&cs2) EnterCriticalSection(&x);

cout<<\顾客B\<

WaitForSingleObject(s2,INFINITE);//p(&s2) EnterCriticalSection(&x);

cout<<\顾客B\<

ReleaseSemaphore(seat,1,NULL);//v(&seat) EnterCriticalSection(&c_seat); seat_num++;

LeaveCriticalSection(&c_seat); if(seat_num<=0) { }

EnterCriticalSection(&x);

cout<<\顾客B\<

EnterCriticalSection(&x);

cout<<\门外还剩\<

DWORD WINAPI consumer3(PVOID c3pv)//顾客对理财线程代码 {

cout<<\这是第\<

srand((unsigned)time(0)); int n=rand()%2; if( seat_num<=0&&n==1) {

EnterCriticalSection(&x);

cout<<\座位已满,该顾客离开!\<

}

else if(seat_num<=0) { }

EnterCriticalSection(&c_seat); seat_num--;

LeaveCriticalSection(&c_seat);

//WaitForSingleObject(seat,INFINITE);//p(&seat) WaitForSingleObject(mutex,INFINITE);//p(&mutex) EnterCriticalSection(&nu3); number3++;

LeaveCriticalSection(&nu3); //EnterCriticalSection(&y); number++;

//LeaveCriticalSection(&y); m3++;

int temp3=number3; EnterCriticalSection(&x);

cout<<\顾客\<

cout<<\顾客C\<

WaitForSingleObject(s3,INFINITE);//p(&s2) EnterCriticalSection(&x);

cout<<\顾客C\<

EnterCriticalSection(&coun); amount ++;

LeaveCriticalSection(&coun); EnterCriticalSection(&x);

cout<<\该顾客在门外等待,已有\<

财服务\<

}

Sleep(ServeTime); m3--;

ReleaseSemaphore(seat,1,NULL);//v(&seat) EnterCriticalSection(&c_seat); seat_num++;

LeaveCriticalSection(&c_seat); if(seat_num<=0) { }

EnterCriticalSection(&x);

cout<<\顾客C\<

EnterCriticalSection(&x);

cout<<\门外还剩\<

int main(void)//主程序 {//创建信号量和线程

cout<<\顾客您好,欢迎来到我行,很高兴为您服务!\<

for(n=0;n

ss1[n]=CreateThread(NULL,0,server1,NULL,0,NULL); ss2[n]=CreateThread(NULL,0,server2,NULL,0,NULL); ss3[n]=CreateThread(NULL,0,server3,NULL,0,NULL); for(n=0;n

for(;number

int m=rand()%Customer_time; Sleep(m);

int i=rand()@0; if(i>1&&i<=240) { }

//用随机数来判断顾客是对私还是对公还是理财

c1[n]=CreateThread(NULL,0,consumer1,NULL,0,NULL); n++;

else if(i>240&&i<=320) }

}

Sleep(80);

EnterCriticalSection(&x);

cout<<\循环再这里结束,不再创建新线程\<

cout<<\已服务\<

{ } else { }

c3[n2]=CreateThread(NULL,0,consumer3,NULL,0,NULL); n2++;

c2[n1]=CreateThread(NULL,0,consumer2,NULL,0,NULL); n1++;

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

Top