重庆交通大学
计算机操作系统实验报告
班级: 信息与计算科学二班 姓名: 凯 学号: 631122020203 实验室: 逸夫楼 指导老师: 杨际祥 实验完成时间: 2013 年 5 月 日
实验一:处理机调度算法
实验内容
选择一个调度算法,实现处理机调度。
实验目的
多道系统中,当就绪进程数大于处理机数时,须按照某种策略决定哪些进程优先占用处理机。本实验模拟实现处理机调度,以加深了解处理机调度的工作。
实验内容
设计一个选择调度算法实现处理机调度的程序。
基本思想
先来先服务(FCFS)调度:
按先来后到次序服务,未作优化
短作业优先调度算法:
1.短作业优先调度算法SJF,是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。SJF调度算法能有效地降低作业的平均等待时间,提高系统吞吐量。该算法对长作业不利,完全未考虑作业的紧迫程度。 时间片轮转算法调度:
先选择时间片的个数和每个时间片需要的时间,正在运行的进程每运行一秒其优先权数目加一,即其优先权减小。每个时间片运行结束后,选择进入时间片进程优先权数目最小的进程,开始下一个时间片的运行。如果有进程运行结束,则离开,再在就绪队列中选择优先权数目最小的进程进入。在运行期间,如果有新的进程来到,按优先权大小放入就绪队列中。 高响应优先算法:
短作业优先调度算法 + 动态优先权机制
既考虑作业的执行时间也考虑作业的等待时间,综合了先来先算法和短作业优先两种算法的特点,每次进行调度算法前都要进行一次高响应优先算法响应比的计算 增加系统开销
算法分析
//m1.h
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 10
/********先来先服务,短作业优先,高响应比算法进程控制块定义***********/
typedef struct Proc_identity
{
char name; //进程名
float arrTime; //到达时间
float finTime; //完成时间
float serTime; //服务时间
float waitTime; //等待时间
float prior; //优先权
float rTime; //周转时间
float drTime; //带权周转时间
}Proc_identity,*proc;
/******************时间片轮转算法进程控制块定义***********************/
typedef struct pcb
{
char name[N]; //进程名
int arrTime; //到达时间
int runTime; //运行时间
char state; //运行后的状态
struct pcb *next; //指向下一个PCB
}PCB;
/*************按到达时间的先后顺序对进程排序(冒泡法)******************/
void SortArrTime(struct Proc_identity pro[],int n)
{
int i,j;
struct Proc_identity ptemp;
int flag;
for(i = 1; i < n; i++)
{
flag = 0;
for(j = 0; j < n-i; j++)
{
if(pro[j].arrTime > pro[j+1].arrTime)
{
ptemp = pro[j];
pro[j] = pro[j+1];
pro[j+1] = ptemp;
flag = 1;
}
}
if(flag == 0)
break;
}
}
/****************************先来先服务算法*****************************/
void FCFS(struct Proc_identity pro[],int n)
{
int i;
//初始化第一个到达的进程
pro[0].finTime = pro[0].arrTime + pro[0].serTime;
pro[0].rTime = pro[0].finTime - pro[0].arrTime;
pro[0].drTime = pro[0].rTime / pro[0].serTime;
//处理后续进程
for(i = 1; i < n; i++)
{
if(pro[i].arrTime <= pro[i-1].finTime) //判断后一个进程到达时间是否在第一个未完成之前
{
pro[i].finTime = pro[i-1].finTime + pro[i].serTime;
pro[i].rTime = pro[i].finTime - pro[i].arrTime;
pro[i].drTime = pro[i].rTime / pro[i].serTime;
}
else
{
pro[i].finTime = pro[i].arrTime + pro[i].serTime;
pro[i].rTime = pro[i].finTime - pro[i].arrTime;
pro[i].drTime = pro[i].rTime / pro[i].serTime;
}
}
}
/**********************短作业优先算法**********************************/
void SJF(struct Proc_identity pro[],int n)
{
int i,j,k;
//初始化第一个到达的进程时间
pro[0].finTime = pro[0].arrTime + pro[0].serTime;
//处理剩下的进程的调度时间
for(i = 1; i < n; i++)
{
if(pro[i].arrTime > pro[i-1].finTime)//此时进程到达的时间都大于第一个进程的完成时间
{
pro[i].finTime = pro[i].arrTime + pro[i].serTime;
}
else
{
int count = 0;
for(j = i; j < n; j++) //当第i-1个进程完成时,找出现在到达的第j个进程
{
if(pro[j].arrTime <= pro[i-1].finTime)
count++;
}
struct Proc_identity MinJobProc,temp;
MinJobProc.serTime = pro[i].serTime;//假设当前进程服务时间最短 int x = i;//找出服务时间最短进程的下标
for(k = i+1; k < count+i; k++)//找出服务时间最短的进程
{
if(MinJobProc.serTime > pro[k].serTime)
{
MinJobProc.serTime = pro[k].serTime;
x = k;
}
}
//将最短服务时间的进程赋给i
temp = pro[i];
pro[i] = pro[x];
pro[x] = temp;
pro[i].finTime = pro[i-1].finTime + pro[i].serTime;
}
}
for(i = 0; i < n; i++)
{
pro[i].rTime = pro[i].finTime - pro[i].arrTime;
pro[i].drTime = pro[i].rTime / pro[i].serTime;
}
}
/*************************高响应比算法*********************************/
void GXYB(struct Proc_identity pro[],int n)
{
int i,j;
//初始化第一个到达的进程时间
pro[0].finTime = pro[0].arrTime + pro[0].serTime;
//处理剩下的进程的调度时间
for(i = 1; i < n; i++)
{
pro[i].waitTime = pro[i-1].finTime - pro[i].arrTime;
//计算当前进程的优先权
pro[i].prior = (pro[i].waitTime + pro[i].serTime) / pro[i].serTime;
struct Proc_identity MaxpriorProc,temp;
MaxpriorProc.prior = pro[i].prior; //假设当前进程的优先权最高 int x = i;//找出优先权最高的进程的下标
for(j = i+1; j < n; j++)//找出优先权最高的进程
{
pro[j].waitTime = pro[i-1].finTime - pro[j].arrTime;
pro[j].prior = (pro[j].waitTime + pro[j].serTime) / pro[j].serTime;
if(MaxpriorProc.prior < pro[j].prior)
{
MaxpriorProc.prior = pro[j].prior;
x = j;
}
}
//将优先权最高的进程赋给i
temp = pro[i];
pro[i] = pro[x];
pro[x] = temp;
pro[i].finTime = pro[i-1].finTime + pro[i].serTime;
}
for(i = 0; i < n; i++)
{
pro[i].rTime = pro[i].finTime - pro[i].arrTime;
pro[i].drTime = pro[i].rTime / pro[i].serTime;
}
}
/*************************时间片轮转算法*******************************/
//封装头结点,指针分别指向队头和队尾
typedef struct
{
PCB *front,*rear;
}queue;
//进程队列置空
queue *init()
{
queue *head;
head = (queue*)malloc(sizeof(queue));
head->front = NULL;
head->rear = NULL;
return head;
}
//检验进程队列是否为空
int empty(queue *head)
{
return(head->front ? 0:1);
}
//进程队列入队,从后面一次入队
queue *append(queue *head,char c[N],int arrTime,int rTime,char state) {
PCB *p;
p = (PCB*)malloc(sizeof(PCB));
strcpy(p->name,c);
p->arrTime = arrTime;
p->runTime = rTime;
p->state = state;
p->next = NULL;
if(empty(head))
{
head->front = head->rear = p;
}
else
{
head->rear->next = p;
head->rear = p;
}
return head;
}
//创建进程队列
queue *creat(queue *head)
{
char name[N];
char state = 'R';
int arrTime,rTime,i,n;
printf("请输入初始化进程总数:");
scanf("%d",&n);
for(i = 1;i <= n;i++)
{
fflush(stdin);
printf("\n请输入第%d个进程的名称(如:A,B,C): ",i);
gets(name);
printf("该进程的到达时间: ");
scanf("%d",&arrTime);
printf("该进程需要运行的时间: ");
scanf("%d",&rTime);
printf("\n");
head = append(head,name,arrTime,rTime,state);
}
return head;
}
//输出创建的进程队列
void print(queue *head)
{
PCB *p;
p = head->front;
if(!p)
{
printf("\n时间片轮转调度队列为空!\n");
}
while(p)
{
printf("名称: %s 到达时间: %d 运行时间: %d 态: %c",p->name,p->arrTime,p->runTime,p->state);
printf("\n");
p = p->next;
}
}
/***********************时间片轮转调度算法***************************/
void RR(queue *head,int q)
{
int t=head->front->arrTime,
lt=head->rear->arrTime;
if(head->front->runTime<q)
t=t+head->front->runTime; 状
else
t=t+q;
//进程队列不为空才可调度
while(!empty(head))
{
PCB *p1,*p2;
//第一种情况: 当前运行的时间小于最后一个进程到达的时间做以下操作 while(t<lt)
{
p1=head->front;
printf("时间:%d\t运行的进程:%s\t",t,p1->name);
p1->runTime=p1->runTime-q;
// 1. 运行时间小于0,删除队首 //
if(p1->runTime<=0)
{
p1->state='F';
printf("运行后的状态:%c\n",p1->state);
head->front=p1->next;
free(p1);
}
// 2. 运行时间大于0,向后找位置插入 //
else
{
printf("运行后的状态:%c\n",p1->state);
p2=p1->next;
while(p2->next&&p2->arrTime!=t)
{ p2=p2->next;}
//此时无新进入队列的进程时,有两种情况:1.不用找位置往后插入,队首不变,不做操作 2.找位置往后插入//
if(p2->arrTime!=t)
{
PCB *p3=p1,*p4;
p1->next//
else
}
while(p3->next&&p3->arrTime<t) {p4=p3;p3=p3->next;} if(p3->arrTime>t) { if(p4!=p1)//p1插在p4后,头为p1->next { head->front=p1->next; p1->next=p4->next; p4->next=p1; } else//不做操作// p4=p3=p2=NULL; } else p4=p3=p2=NULL; } //此时有新进入队列的进程时:p1插在新进入队列的进程p2后,队首为 { head->front=p1->next; p1->next=p2->next; p2->next=p1; } } /*时刻变化*/ if(head->front->runTime<q) t=t+head->front->runTime; else t=t+q;
//第二种情况:当前运行的时间大于最后一个进程到达的时间做以下操作 while(t>=lt) { p1=head->front; printf("时间:%d\t运行的进程:%s\t",t,p1->name); p1->runTime=p1->runTime-q; // 1. 运行时间小于0,删除队首 // if(p1->runTime<=0) { p1->state='F'; printf("运行后的状态:%c\n",p1->state); head->front=p1->next; free(p1); } // 2. 运行时间大于0,直接插在队尾 // else { printf("运行后的状态:%c\n",p1->state); } //若原队列只有一个进程,不必往队尾插// if(!p1->next) head->front=p1; //若原队列有多个进程// else { head->front=p1->next; head->rear->next=p1; head->rear=p1; p1->next=NULL; } /*时刻变化,队列为空时不做时刻变化*/ if(empty(head)) return; else {
if(head->front->runTime<q)
t=t+head->front->runTime;
else
t=t+q;
}
}
}
}
/*********************进程运行结果输出模块****************************/
void print(struct Proc_identity Proc[],int n)
{
//计算平均周转时间和平均带权周转时间
float sumrTime = 0,sumdrTime = 0;
float avgrTime = 0,avgdrTime = 0;
for(int i = 0; i < n; i++)
{
sumrTime += Proc[i].rTime;
sumdrTime += Proc[i].drTime;
}
avgrTime = sumrTime / n;
avgdrTime = sumdrTime /n;
printf("名称\t到达\t服务\t完成\t周转\t带权周转\n");
for(i = 0; i < n; i++)
{
printf("%-7c\t%-7.0f\t%-7.0f\t%-7.0f\t%-7.0f\t%-7.2f\n",
Proc[i].name,Proc[i].arrTime,Proc[i].serTime,Proc[i].finTime,Proc[i].rTime,Proc[i].drTime);
}
printf("平均:\t\t\t\t%-7.2f\t%-7.2f\n",avgrTime,avgdrTime);
}
/*********************进程初始化模块****************************/
int create(struct Proc_identity Proc[])
{
int n,i;
printf("请输入初始化进程总数: ");
scanf("%d",&n);
for(i = 0; i < n; i++)
{
fflush(stdin);
printf("\n请输入第%d个进程的名称(如:A,B,C): ",i+1);
scanf("%c",&Proc[i].name);
printf("该进程的到达时间: ");
scanf("%f",&Proc[i].arrTime);
printf("该进程的服务时间: ");
scanf("%f",&Proc[i].serTime);
printf("\n");
}
return n;
}
/**************************************主函数的
********************************************/
//main.cpp
#include<stdio.h>
#include<m1.h>
int main()
{
Loop:
fflush(stdin);
char flag;
struct Proc_identity Proc[N];
printf("++++++++++++++++++++++++处理机调度算
++++++++++++++++++++++++++\n");
printf("+ +\n"); 定义模法模拟系块统
printf("+ 1.[F] 先来先服务算法 +\n");
printf("+ 2.[S] 短作业优先算法 +\n");
printf("+ 3.[T] 时间片轮转算法 +\n");
printf("+ 4.[P] 高响应优先算法 +\n");
printf("+ 5.[E] 结 束 +\n");
printf("+
+\n");
printf("+ 说明: R:Running(运行状态),F:Finished(完成状态). +\n");
printf("+
+\n");
printf("+++++++++++++++++++++++请先输入相应操作的标识符
+++++++++++++++++++++++++\n\n");
printf("输入:");
scanf("%c",&flag);
if(flag == 'F' || flag=='f')
{
printf("\n您选择的是'先来先服务'算法\n\n");
int n = create(Proc);
FCFS(Proc,n);
printf("***********************先来先服务***********************\n\n");
print(Proc,n);
printf("\n********************************************************\n\n\n");
}
else if(flag == 'S' || flag == 's')
{
printf("\n您选择的是'短作业优先'算法\n\n");
int n = create(Proc);
SJF(Proc,n);
printf("***********************短作业优先***********************\n\n");
print(Proc,n);
printf("\n********************************************************\n\n\n");
} } else if(flag=='T'||flag=='t') { printf("\n您选择的是'时间片轮转'算法\n\n"); queue *head;int q; head=init(); head=creat(head); printf("\n您输入的时间片轮转进程队列为:\n\n"); print(head); printf("\n请输入时间片轮转调度的时间片为:"); scanf("%d",&q); printf("\n"); RR(head,q); printf("\n"); } else if(flag=='P'||flag=='p') { printf("\n您选择的是'高响应比优先'算法\n\n"); int n = create(Proc); GXYB(Proc,n); printf("***********************高响应比优先*********************\n\n"); print(Proc,n); printf("\n********************************************************\n\n\n"); } else if(flag=='E'||flag=='e') { return 0; } goto Loop;
输出结果
实验总结
通过本次实验,让自己掌握了先来先算法、短作业算法、时间轮转算法以及高响应算法的基本思想,同时增强了自己对程序的理解水平。
在选择调度开关时 可以选择switch语句 更加方便理解
实验二:资源分配银行家算法
实验内容
设计五个进程{P0,P1,P2,P3,P4}共享三类资源{A,B,C}的系统,{A,B,C}的资源数量分别为10,5,7。进程可动态地申请资源和释放资源,系统按各进程的申请动态地分配资源。要求程序具有显示和打印各进程的某一时刻的资源分配表和安全序列;显示和打印各进程依次要求申请的资源号以及为某进程分配资源后的有关资源数据 实验目的
在了解和掌握银行家算法的基础上,能熟练的处理课本例题中所给状态的安全性问题,能编制银行家算法通用程序。
实验内容
设计五个进程{P0,P1,P2,P3,P4}共享三类资源{A,B,C}的系统,{A,B,C}的资源数量分别为10,5,7。进程可动态地申请资源和释放资源,系统按各进程的申请动态地分配资源。要求程序具有显示和打印各进程的某一时刻的资源分配表和安全序列;显示和打印各进程依次要求申请的资源号以及为某进程分配资源后的有关资源数据。 算法分析
//m1.h
#include<stdio.h>
#define TRUE 1
#define FALSE 0
#define M 5
#define N 3
//m2.h
#include<m1.h>
int available[N]={3,3,2};
int max[M][N]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};
int allocation[M][N]={{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};
int need[M][N],p[M];
void init(){
int i,j;
for(i=0;i<M;i++){
for(j=0;j<N;j++){
need[i][j]=max[i][j]-allocation[i][j];
}
}
}
void output(){
int i,j;
printf("\n已分配资源情况如下:");
for(i=0;i<M;i++){
printf("\nP[%d]: ",i);
for(j=0;j<N;j++){
printf(" %d ",allocation[i][j]);
}
}
}
int compare(int need[],int work[]){
int j;
for(j=0;j<N;j++){
if(need[j]>work[j]){
return FALSE;
}
}
return TRUE;
}
int isSecurity(int available[],int need[][N],int allocation[][N]){ int i,j,k=0,flag,finish[M],work[N];
for(i=0;i<M;i++){
finish[i]=FALSE;
}
for(j=0;j<N;j++){
work[j]=available[j];
}
while(TRUE){
flag=FALSE;
for(i=0;i<M;i++){
if(finish[i]==FALSE&&compare(need[i],work)==TRUE){ for(j=0;j<N;j++){
work[j]+=allocation[i][j];
}
finish[i]=TRUE;
p[k++]=i;
flag=TRUE;
break;
}
}
if(flag==FALSE){
for(i=0;i<M;i++){
if(finish[i]==FALSE) return FALSE;
}
return TRUE;
}
}
}
void operate(){
int i,j,flag,f1,request[N];
printf("****************************************************************\n"); printf("当输入的数小于0时,停止运行!\n");
while(TRUE){
f1=FALSE;
printf("请输入进程号 :\n"); scanf("%d",&i); if(i>=M){ printf("此进程不存在,请重新输入!\n"); continue; } getchar(); if(i<0) break;
printf("请输入请求向量:\n");
for(j=0;j<N;j++){
scanf("%d",&request[j]);
}
for(j=0;j<N;j++){
if(request[j]>need[i][j]){
printf("该进程申请的资源数大于其所需要的资源数!\n申请不合理,出错!\n");
output();
printf("\n**************************************************************\n"); f1=TRUE;
break;
}
}
for(j=0;j<N&&f1==FALSE;j++){
if(request[j]>available[j]){
printf("该进程申请的资源数大于系统当前可用资源数!***请等待!\n"); output();
printf("\n**************************************************************\n"); f1=TRUE;
break;
}
}
if(f1==TRUE) continue;
for(j=0;j<N;j++){
available[j]-=request[j];
allocation[i][j]+=request[j];
need[i][j]-=request[j];
}
flag=isSecurity(available,need,allocation);
if(flag==TRUE){
printf("存在安全序列如下:\n");
for(i=0;i<M;i++){
i==4 ? printf("P[%d]",i) : printf("P[%d]-->",p[i]);
}
printf("\n此时系统是安全状态,将所申请的资源分配给它!\n");
output();
printf("\n**************************************************************\n"); }
else{
printf("\n此时系统进入不安全状态, 不分配资源!***请等待!\n"); for(j=0;j<N;j++){
available[j]-=request[j];
allocation[i][j]+=request[j];
need[i][j]-=request[j];
}
output();
printf("\n*************************************************************\n"); }
}
}
Main.cpp
#include <m1.h>
#include <m2.h>
void main(){
init();
operate();
}
实验结果
实验总结
(1)当输入的进程号为1,请求向量为(1,0,2)时,因为存在一个安全序列P[1]-->P[3]-->P[0]-->P[2]-->P[4],系统是安全的,故将资源分配给它。
(2)当输入的进程号为4,请求向量为(3,3,0)时,因为该进程申请的资源数大于系统当前可用资源数,故等待。
(3)当输入的进程号为0,请求向量为(0,2,0)时,因为此时系统进入不安全状态,
不
分配资源,故等待!
(4)当输入的进程号为6,因为此进程不存在 ,需要重新输入。
(5)当输入的进程号为3,请求向量为(5,6,8)时,因为申请的资源数大于其所需要的资源数,故出错。
(6)当输入的进程号为-1时,因为小于0,故程序停止运行。
此次实验不仅结果与预期的结果一样,还考虑了容错处理,例如:进程号小于0,所输进程不存在等情况
通过此实验熟练的掌握了利用高级语言C语言编写和调试一个动态分配资源的简单程序,加深了解了死锁产生的条件和原因。通过编程实现银行家算法来预防死锁,清楚的了解了安全性算法的相关内容,加深了对课堂上所讲内容的理解。
实验三生产者和消费者问题
实验内容
以生产者/消费者模型为依据,创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
实验目的
以生产者和消费者问题为例,学习进程通信、同步机制的具体实现方法,主要是信号量和共享内存。
算法分析
#include <windows.h>
#include <iostream>
#include<cstdio>
const int PCOUNT = 5; //生产者的个数 const int CCOUNT = 5; //消费者的个数 const int N = 8; //缓冲池中缓冲区数量 int ProductID = 0; //生产产品号 int ConsumeID = 0; //消费产品号 int in = 0;
int out = 0;
int total = 0; //库存量
int Buffer[N]; //缓冲池 int buffer[N];
bool stop = false;
HANDLE Mutex; //互斥信号量实现缓冲池的互斥使用
HANDLE Full; //缓冲池中满缓冲区的数量
HANDLE Empty; //缓冲池中空缓冲区的数量
SYSTEMTIME systime;
DWORD WINAPI Producer(LPVOID); //生产者线程
DWORD WINAPI Consumer(LPVOID); //消费者线程
int main()
{
//创建各个互斥信号
Mutex = CreateMutex(NULL,FALSE,NULL);
Full = CreateSemaphore(NULL,N-1,N-1,NULL);
Empty = CreateSemaphore(NULL,0,N-1,NULL);
//创建互斥信号量失败
if (Mutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return 0;
}
//创建Full信号量失败
if (Full == NULL)
{
printf("CreateSemaphoreFull error: %d\n", GetLastError());
return 0;
}
//创建Empty信号量失败
if (Empty == NULL)
{
printf("CreateSemaphoreEmpty error: %d\n", GetLastError());
return 0;
}
HANDLE ProducerThreads[PCOUNT]; //生产者线程 HANDLE ConsumerThreads[CCOUNT]; //消费者线程 DWORD producerID[PCOUNT]; //生产者线程的标识符 DWORD consumerID[CCOUNT]; //消费者线程的标识符
//创建生产者线程
for (int i=0;i<PCOUNT;++i)
{
ProducerThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]); if(ProducerThreads[i] == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return 0;
}
}
//创建消费者线程
for (i=0;i<CCOUNT;++i)
{
ConsumerThreads[i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]); if( ConsumerThreads[i] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 0;
}
}
while(!stop)
{
if(getchar())//按回车后终止程序运行
{
stop = true;
}
}
return 0;
}
//生产
void Produce()
{
printf("生产第%d个产品并加入库存中\n",++ProductID );
Buffer[in] = 1;
in = (in+1)%N;
//输出缓冲区当前的状态
printf("缓冲区当前的状态:");
for (int i=0;i<N;++i)
{
printf("%d",Buffer[i]);
}
printf("\n");
printf("生产者ID:%d\n",GetCurrentThreadId());
buffer[in-1] = GetCurrentThreadId();
printf("产品ID:%d\t\t缓冲区ID:%d\n",ProductID,in);
GetLocalTime(&systime);
printf("时间:%02d:%02d:%02d\t\t", systime.wHour, systime.wMinute, systime.wSecond); printf("当前库存量:%d\n",++total);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); }
//消费
void Consume()
{
printf("消费第%d个产品并从库存拿出\n",++ConsumeID); Buffer[out] = 0;
out = (out+1)%N;
//输出缓冲区当前的状态
printf("缓冲区当前的状态:");
for (int i=0;i<N;++i)
{
printf("%d",Buffer[i]);
}
printf("\n");
printf("消费者ID:%d\n",GetCurrentThreadId()); printf("产品ID:%d\t\t缓冲区ID:%d\n",ConsumeID,out,buffer[out-1]);
GetLocalTime(&systime);
}
ID:%d\t\t来自生产者printf("时间:%02d:%02d:%02d\t\t", systime.wHour, systime.wMinute, systime.wSecond); printf("当前库存量:%d\n",--total); printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//生产者
DWORD WINAPI Producer(LPVOID lpPara)
{
while(!stop)
{
WaitForSingleObject(Full,INFINITE);
WaitForSingleObject(Mutex,INFINITE);
Produce();
Sleep(1000);
ReleaseMutex(Mutex);
ReleaseSemaphore(Empty,1,NULL);
}
return 0;
}
//消费者
DWORD WINAPI Consumer(LPVOID lpPara)
{
while(!stop)
{
WaitForSingleObject(Empty,INFINITE);
WaitForSingleObject(Mutex,INFINITE);
Consume();
Sleep(1000);
ReleaseMutex(Mutex);
ReleaseSemaphore(Full,1,NULL);
}
return 0;
}
实验结果
实验总结
<1>在每个程序中坐须先做P(Mutex),后做V(Mutex),二者要成对出现。夹在二者中间的代码段就是该进程的临界区。
<2>对同步信号量Full和Empty的P,V操作同样必须成对出现,但它们分别位于不同的程序中。
<3>无论在生产者进程中还是在消费者进程中,两个P操作的次序不能颠倒:应先执行同 步信号量的P操作,然后执行互斥信号量的P操作。否则可能造成进程死锁。