北邮 操作系统 实验一 进程同步
操作系统实验一-进程同步
实验一进程同步一、实验目的:分析进程的同步与互斥现象,编程实现经典的进程同步问题——生产者与消费者问题的模拟,进一步加深对进程同步与互斥的理解。
二、实验内容:用C语言实现对生产者与消费者问题的模拟。
实验原理:生产者和消费者是经典的进程同步问题,在这个问题中,生产者不断的向缓冲区中写入数据,而消费者则从缓冲区中读取数据。
生产者进程和消费者对缓冲区的操作是互斥,即当前只能有一个进程对这个缓冲区进行操作,生产者进入操作缓冲区之前,先要看缓冲区是否已满,如果缓冲区已满,则它必须等待消费者进程将数据取出才能写入数据,同样的,消费者进程从缓冲区读取数据之前,也要判断缓冲区是否为空,如果为空,则必须等待生产者进程写入数据才能读取数据。
三、实验准备:1. 实现步骤:(1)分析计算机系统中对资源的分配与释放过程:计算机系统中的每个进程都可以消费或生产某类资源。
当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。
而当某个进程释放资源时,则它就相当一个生产者。
(2)定义生产者消费者问题中的各数据结构,并初始化信号量;(3)创建生产者与消费者进程,利用信号量实现生产者与消费者之间的同步与互斥;最后编程实现。
2. 相关函数:在实现的过程中需要用到以下API函数:(1)CreateThread()//该函数创建一个在调用进程的地址空间中执行的线程。
若线程创建成功,将返回该线程的句柄。
函数原型:HANDLE CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, //描述安全性,用NULL表示使用缺省值DWORD dwStackSize, //新线程拥有自己的堆栈,0表示使用缺省值1MB,推荐LPTHREAD_START_ROUTINE lpStartAddress, //新线程的起始地址,放线程函数名称LPVOID lpParameter,//此值被传送到线程函数去作为参数DWORD dwCreationFlags,//允许产生一个暂时挂起的线程,默认是0立即开始执行LPDWORD lpThreadld );//新线程的ID被传到这用法举例:hHandle1 = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,0,(LPTHREAD_START_ROUTINE) ThreadName1,(LPVOID) NULL,0, &dwThreadID1 );(2)CreateMutex()函数可用来创建一个有名或无名的互斥量对象,函数返回值为互斥对象的句柄。
进程同步实验报告
一、实验目的1. 理解进程同步的概念和原理;2. 掌握进程同步的基本方法和机制;3. 学会使用信号量实现进程同步;4. 通过实验验证进程同步机制的有效性。
二、实验原理1. 进程同步:在多道程序设计中,进程的执行是并发的,但某些情况下需要保证多个进程按照一定的顺序执行,以避免出现数据不一致、死锁等问题。
进程同步是指通过某种机制,协调多个进程的执行顺序,保证它们能够正确、有效地共享资源。
2. 信号量:信号量是一种特殊的变量,用于实现进程同步。
信号量具有两个原子操作:P操作(wait)和V操作(signal)。
P操作用于申请资源,V操作用于释放资源。
3. 互斥锁:互斥锁是一种常见的进程同步机制,用于保证临界资源的互斥访问。
当一个进程进入临界区时,它会尝试获取互斥锁,如果锁已被其他进程获取,则该进程进入等待状态;当进程退出临界区时,它会释放互斥锁。
三、实验内容1. 实验环境:Linux操作系统,C语言编程环境。
2. 实验工具:gcc编译器、gdb调试器。
3. 实验步骤:(1)创建一个互斥锁,用于保护临界资源。
(2)编写两个进程,分别模拟对临界资源的访问。
(3)在进程访问临界资源前,使用P操作尝试获取互斥锁。
(4)在进程访问临界资源后,使用V操作释放互斥锁。
(5)编译并运行程序,观察进程执行情况。
四、实验结果与分析1. 实验结果:(1)在互斥锁的保护下,两个进程能够按照预期顺序访问临界资源。
(2)当其中一个进程正在访问临界资源时,另一个进程会进入等待状态。
(3)当进程访问临界资源完成后,它会释放互斥锁,允许其他进程访问。
2. 实验分析:(1)互斥锁能够有效地保护临界资源,避免数据不一致问题。
(2)信号量P操作和V操作保证了进程的同步,避免了死锁现象。
(3)通过实验验证了进程同步机制的有效性。
五、实验总结本次实验通过使用信号量和互斥锁,实现了进程同步。
实验结果表明,信号量和互斥锁能够有效地保证进程按照预期顺序执行,避免数据不一致和死锁等问题。
操作系统实验进程同步与互斥
操作系统实验进程同步与互斥操作系统实验进程同步与互斥实验目的1.掌握进程同步和互斥原理,理解生产者-消费者模型;2.学习Windows2000/xp中的多线程并发执行机制;3.学习使用Windows SDK解决读者-写者问题。
试验内容1依据生产者-消费者模型,在Windows 2000/xp环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥,分析、熟悉生产者消费者问题仿真的原理和实现技术。
(见附件2)试验内容2参考实验内容1和附件2伪码,编程解决读者-写者问题的程序。
(具体要求和读写者问题原始伪码内容见附件1)相关知识Windows 2000/XP的线程控制CreateThread完成线程创建,在调用进程的地址空间上创建一个线程,以执行指定的函数;它的返回值为所创建线程的句柄。
ExitThread用于结束当前线程。
SuspendThread可挂起指定的线程。
ResumeThread可激活指定线程,它的对应操作是递减指定线程的挂起计数,当挂起计数减为0时,线程恢复执行。
Windows 2000/XP的进程互斥和同步在Windows 2000/XP中提供了临界区、互斥对象、信号量对象同步对象和相应的系统调用,用于进程和线程同步。
临界区对象(Critical Section)只能用于在同一进程内使用的临界区,同一进程内各线程对它的访问是互斥进行的。
相关API包括:InitializeCriticalSection对临界区对象进行初始化;EnterCriticalSection等待占用临界区的使用权,得到使用权时返回;TryEnterCriticalSection非等待方式申请临界区的使用权;申请失败时,返回0;LeaveCriticalSection释放临界区的使用权;DeleteCriticalSection释放与临界区对象相关的所有系统资源。
互斥对象(Mutex)互斥对象相当于互斥信号量,在一个时刻只能被一个线程使用。
2.实验:进程的同步和互斥
《操作系统实验》
实验一:进程的同步和互斥
黄伯虎
实验内容
生产者消费者问题实现
描述:
假设存在两类进程:生产者,消费者。
它们共享n个缓冲区。
生产者行为:生产产品(每次生产1个),并将产品放入空缓冲区,循环往复,永不停息;
消费者行为:将产品从缓冲区中取出,进行消费(每次消费1个),循环往复,永不停息。
规定:缓冲区满,生产者不能放产品;缓冲区空,消费者不能取产品
要求
基本要求
实现当n=1,生产者、消费者各为1个时,同步和互斥过程
扩展要求(可选)
实现当n=c(整常数),生产者、消费者有多个(>1)时,同步和互斥过程平台和工具(原则不限,推荐如下)
Win32平台
VC++6.0
结果显示
字符界面,能说明问题即可
最终成果形式
提交实验报告1份(格式参见附件A)
报告提交时限:下一次实验开始前
提交形式:email
提交的邮件主题请按照如下格式书写:“学号+姓名+实验名称.rar/.doc”
如“030811300+张三+进程同步与互斥.rar/.doc”提交地址:
13班:xdos1@
14,31班:xdos2@。
操作系统进程同步实验报告1
操作系统进程同步实验报告实验三:进程同步实验一、实验任务:(1)掌握操作系统的进程同步原理;(2)熟悉linux的进程同步原语;(3)设计程序,实现经典进程同步问题。
二、实验原理:(1)P、V操作PV操作由P操作原语与V操作原语组成(原语就是不可中断的过程),对信号量进行操作,具体定义如下:P(S):①将信号量S的值减1,即S=S-1;②如果S30,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):①将信号量S的值加1,即S=S+1;②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
(2)信号量信号量(semaphore)的数据结构为一个值与一个指针,指针指向等待该信号量的下一个进程。
信号量的值与相应资源的使用情况有关。
当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。
注意,信号量的值仅能由PV 操作来改变。
一般来说,信号量S30时,S表示可用资源的数量。
执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S(3)linux的进程同步原语①wait();阻塞父进程,子进程执行;②#include#includekey_t ftok (char*pathname, char proj);它返回与路径pathname相对应的一个键值。
③int semget(key_t key, int nsems, int semflg)参数key就是一个键值,由ftok获得,唯一标识一个信号灯集,用法与msgget()中的key 相同;参数nsems指定打开或者新创建的信号灯集中将包含信号灯的数目;semflg参数就是一些标志位。
参数key与semflg的取值,以及何时打开已有信号灯集或者创建一个新的信号灯集与msgget()中的对应部分相同。
该调用返回与健值key相对应的信号灯集描述字。
调用返回:成功返回信号灯集描述字,否则返回-1。
操作系统进程调度和进程同步实验要求
0711操作系统进程调度和进程同步实验要求实验内容:用线程模拟进程,实现进程调度和进程同步。
在任意操作系统中,用c、c++或者java 编写程序。
并且完成相应的实验报告。
实验要求:实验一:进程调度⑴ 主线程,创建子线程,保存子线程的虚拟PCB(参见恐龙书P74)、要求运行多少时间(可随机产生)、已经等待多少时间(初始化为0),优先级(可随机产生)等信息,并负责子线程的调度。
调度的基本时间单位为1 S。
⑵ 创建20个线程(可以只用一个线程函数,传递不同的参数即上述数据结构)分别实现FCFS调度、SJF调度、RR调度、优先级调度和多级队列调度,并且计算每个调度的平均等待时间。
其中,多级队列调度要求设计4个调度队列,每个队列5个线程,队列内部分别采用FCFS、SJF、RR和优先级调度。
时间片的长度可以随机生成为n S。
⑶ 对于每个子线程,在其运行期间,输出其占用的时间标号(例如,第3个线程占用了第10秒的CPU时间,输出为:“Thread 3: 10”,格式可自行设计)。
实验二:进程同步⑴ 模拟哲学家就餐问题:设置5个子线程模拟5个哲学家,设置5个互斥区为筷子。
⑵ 输出问题解决方法:在每个哲学家线程中输出其获得的筷子标号与时间(可以读取系统时间,或者自行设置时间标准),例如:哲学家2在第n秒获得筷子1,在第m秒获得筷子2。
实验报告要求:写明实验目的、实验设计步骤、实验结果、总结。
附录:windows线程基本操作以windows线程函数为例介绍线程基本操作,以下函数都必须包含windows.h头文。
如果想更深入地了解线程,请参见《c++编程艺术》等相关书籍。
线程创建函数:HANDLE CreateThread (LPSECURITY_ATTRIBUTES secAttr,SIZE_T stackSize,LPTHREAD_START_ROUTINE threadFunc,LPVOID param,DWORD flags,LPDWORD threadID);在此,secAttr是一个用来描述线程的安全属性的指针。
操作系统实验报告——进程同步与互斥
操作系统实验报告——进程同步与互斥一、实验内容本实验主要内容是通过编写程序来实现进程的同步与互斥。
具体来说,是通过使用信号量来实现不同进程之间的同步和互斥。
我们将编写两个进程,一个进程负责打印奇数,另一个进程负责打印偶数,两个进程交替打印,要求打印的数字从1开始,直到100结束。
二、实验原理进程的同步是指多个进程之间按照一定的顺序执行,进程之间互相等待的关系。
而进程的互斥是指多个进程竞争同一个资源,需要通过其中一种方式来避免同时访问共享资源,以免造成数据错乱。
在本实验中,我们使用信号量来实现进程的同步与互斥。
信号量是一个计数器,用于表示一些共享资源的可用数量。
进程在访问共享资源时,需要先对信号量进行操作,当信号量大于0时,表示资源可用,进程可以访问;当信号量等于0时,表示资源不可用,进程需要等待。
进程同步的实现可以通过信号量的P操作与V操作来完成。
P操作用于申请资源,当资源可用时,将计数器减一,并进入临界区;V操作用于释放资源,当资源使用完毕时,将计数器加一,使等待资源的进程能够申请。
进程互斥的实现可以通过信号量的P操作与V操作结合临界区来完成。
当多个进程需要访问共享资源时,需要先进行P操作,进入临界区,访问完毕后进行V操作,离开临界区。
三、实验步骤1.首先,我们需要创建两个进程,一个进程负责打印奇数,另一个进程负责打印偶数。
2. 然后,我们创建一个共享变量count,用来记录打印的数字。
3. 接着,我们创建两个信号量odd和even,用来控制进程的同步与互斥。
odd信号量初始值为1,表示打印奇数的进程可以访问;even信号量初始值为0,表示打印偶数的进程需要等待。
4.编写奇数打印进程的代码,首先进行P操作,判断奇数信号量是否大于0,如果大于0,表示可以打印奇数。
5. 如果可以打印奇数,将count加一,并输出当前的奇数,然后进行V操作,释放偶数打印进程的等待。
6.同样的,编写偶数打印进程的代码,首先进行P操作,判断偶数信号量是否大于0,如果大于0,表示可以打印偶数。
操作系统-进程管理与进程同步-实验报告
实验一、进程管理与进程同步一、实验目的了解进程管理的实现方法,理解和掌握处理进程同步问题的方法。
二、实验内容实现银行家算法、进程调度过程的模拟、读者-写者问题的写者优先算法。
实验步骤:理解安全性算法和银行家算法的核心机制:针对3类资源、5个进程的情况,设计相应的数据结构,分别表示每个进程占用各类资源的情况;编程实现安全性算法函数,编制主函数,动态输入资源的占用情况,进程的资源申请,调用安全性函数,实现银行家算法;测试:输入可分配和不可分配的请求,测试系统的正确性。
三、实验环境Windows 2000;Microsoft Visual C++ 6.0四、程序源码与运行结果银行家算法代码:#include "malloc.h"#include "stdio.h"#include "stdlib.h"#define alloclen sizeof(struct allocation)#define maxlen sizeof(struct max)#define avalen sizeof(struct available)#define needlen sizeof(struct need)#define finilen sizeof(struct finish)#define pathlen sizeof(struct path)struct allocation{int value;struct allocation *next;};struct max{int value;struct max *next;};struct available /*可用资源数*/{int value;struct available *next;};struct need /*需求资源数*/{int value;struct need *next;};struct path{int value;struct path *next;};struct finish{int stat;struct finish *next;};int main(){int row,colum,status=0,i,j,t,temp,processtest;struct allocation *allochead,*alloc1,*alloc2,*alloctemp;struct max *maxhead,*maxium1,*maxium2,*maxtemp;struct available *avahead,*available1,*available2,*workhead,*work1,*work2,*worktemp,*worktemp1; struct need *needhead,*need1,*need2,*needtemp;struct finish *finihead,*finish1,*finish2,*finishtemp;struct path *pathhead,*path1,*path2;printf("\n请输入系统资源的种类数:");scanf("%d",&colum);printf("请输入现时内存中的进程数:");scanf("%d",&row);printf("请输入已分配资源矩阵:\n");for(i=0;i<row;i++){for (j=0;j<colum;j++){printf("请输入已分配给进程 p%d 的 %c 种系统资源:",i,'A'+j);if(status==0){allochead=alloc1=alloc2=(struct allocation*)malloc(alloclen);alloc1->next=alloc2->next=NULL;scanf("%d",&allochead->value);status++;}else{alloc2=(struct allocation *)malloc(alloclen);scanf("%d,%d",&alloc2->value);if(status==1){allochead->next=alloc2;status++;}alloc1->next=alloc2;alloc1=alloc2;}}}alloc2->next=NULL;status=0;printf("请输入最大需求矩阵:\n");for(i=0;i<row;i++){for (j=0;j<colum;j++){printf("请输入进程 p%d 种类 %c 系统资源最大需求:",i,'A'+j);if(status==0){maxhead=maxium1=maxium2=(struct max*)malloc(maxlen);maxium1->next=maxium2->next=NULL;scanf("%d",&maxium1->value);status++;}else{maxium2=(struct max *)malloc(maxlen);scanf("%d,%d",&maxium2->value);if(status==1){maxhead->next=maxium2;status++;}maxium1->next=maxium2;maxium1=maxium2;}}}maxium2->next=NULL;status=0;printf("请输入现时系统剩余的资源矩阵:\n");for (j=0;j<colum;j++){printf("种类 %c 的系统资源剩余:",'A'+j);if(status==0){avahead=available1=available2=(struct available*)malloc(avalen); workhead=work1=work2=(struct available*)malloc(avalen);available1->next=available2->next=NULL;work1->next=work2->next=NULL;scanf("%d",&available1->value);work1->value=available1->value;status++;}else{available2=(struct available*)malloc(avalen);work2=(struct available*)malloc(avalen);scanf("%d,%d",&available2->value);work2->value=available2->value;if(status==1){avahead->next=available2;workhead->next=work2;status++;}available1->next=available2;available1=available2;work1->next=work2;work1=work2;}}available2->next=NULL;work2->next=NULL;status=0;alloctemp=allochead;maxtemp=maxhead;for(i=0;i<row;i++)for (j=0;j<colum;j++){if(status==0){needhead=need1=need2=(struct need*)malloc(needlen); need1->next=need2->next=NULL;need1->value=maxtemp->value-alloctemp->value;status++;}else{need2=(struct need *)malloc(needlen);need2->value=(maxtemp->value)-(alloctemp->value); if(status==1)needhead->next=need2;status++;}need1->next=need2;need1=need2;}maxtemp=maxtemp->next;alloctemp=alloctemp->next;}need2->next=NULL;status=0;for(i=0;i<row;i++){if(status==0){finihead=finish1=finish2=(struct finish*)malloc(finilen); finish1->next=finish2->next=NULL;finish1->stat=0;status++;}else{finish2=(struct finish*)malloc(finilen);finish2->stat=0;if(status==1){finihead->next=finish2;status++;}finish1->next=finish2;finish1=finish2;}}finish2->next=NULL; /*Initialization compleated*/status=0;processtest=0;for(temp=0;temp<row;temp++){alloctemp=allochead;needtemp=needhead;finishtemp=finihead;worktemp=workhead;for(i=0;i<row;i++)worktemp1=worktemp;if(finishtemp->stat==0){for(j=0;j<colum;j++,needtemp=needtemp->next,worktemp=worktemp->next) if(needtemp->value<=worktemp->value)processtest++;if(processtest==colum){for(j=0;j<colum;j++){worktemp1->value+=alloctemp->value;worktemp1=worktemp1->next;alloctemp=alloctemp->next;}if(status==0){pathhead=path1=path2=(struct path*)malloc(pathlen);path1->next=path2->next=NULL;path1->value=i;status++;}else{path2=(struct path*)malloc(pathlen);path2->value=i;if(status==1){pathhead->next=path2;status++;}path1->next=path2;path1=path2;}finishtemp->stat=1;}else{for(t=0;t<colum;t++)alloctemp=alloctemp->next;finishtemp->stat=0;}}elsefor(t=0;t<colum;t++){needtemp=needtemp->next;alloctemp=alloctemp->next;}processtest=0;worktemp=workhead;finishtemp=finishtemp->next;}}path2->next=NULL;finishtemp=finihead;for(temp=0;temp<row;temp++){if(finishtemp->stat==0){printf("\n系统处于非安全状态!\n"); exit(0);}finishtemp=finishtemp->next;}printf("\n系统处于安全状态.\n"); printf("\n安全序列为: \n");do{printf("p%d ",pathhead->value);}while(pathhead=pathhead->next);printf("\n");return 0;}运行结果:备注:输入数据为P110 银行家算法之例所用数据《计算机操作系统》(第三版)西安电子科技大学出版社银行家算法原理说明:银行家算法是一种最有代表性的避免死锁的算法。
操作系统实验-进程同步与互斥
操作系统实验-进程同步与互斥实验四:进程的管道通信实验题目进程的管道通信实验目的加深对进程概念的理解,明确进程和程序的区别。
学习进程创建的过程,进一步认识进程并发执行的实质。
分析进程争用资源的现象,学习解决进程互斥的方法。
学习解决进程同步的方法。
掌握Linux系统中进程间通过管道通信的具体实现实验内容使用系统调用pipe()建立一条管道,系统调用fork()分别创建两个子进程,它们分别向管道写一句话,如:Child process1 is sending a message!Child process2 is sending a message!父进程分别从管道读出来自两个子进程的信息,显示在屏幕上。
当然,仅仅通过屏幕上输出这两句话还不能说明实现了进程的管道通信,为了能够更好的证明和显示出进程的同步互斥和通信,在其中要加入必要的跟踪条件,如一定的输出语句等,来反映程序的并发执行情况实验要求这是一个设计型实验,要求自行、独立编制程序。
两个子进程要并发执行。
实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。
实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
为了清楚的反应进程的同步,在子进程完成相应的操作后,调用sleep()函数睡眠一段时间(程序中定为3s)。
父进程先执行wait()函数,当有子进程执行完毕后,会得到子进程的返回结果并清理子进程。
若子进程没执行完,父进程一直执行wait()进行监听,知道有一个子进程执行完成为僵尸进程。
程序中用到的系统调用因为程序时在linux系统上进行编写的,所以其中要利用到相关的linux提供的系统调用。
所用到的系统调用包含在如下头文件中。
#include#include#include#include#include#includefork() 用于创一个子进程。
操作系统实验报告——进程同步与互斥
《进程同步与互斥》实验报告实验序号:01 实验项目名称:进程同步与互斥学号姓名专业、班实验地点指导教师时间一、实验目的1、掌握基本的进程同步与互斥算法,理解生产者-消费者问题。
2、学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。
3、了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步与互斥。
4、设计程序,实现生产者-消费者进程(线程)的同步与互斥;二、实验环境Windows 2000/XP + Visual C++ 6.0三、实验容以生产者-消费者模型为依据,在Windows 2000/XP环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
四、设计思路和流程框图生产者进程的功能:生产东西,供消费者消费;消费者进程的功能:消费生产者生产的东西。
生产者生产产品并存入缓冲区供消费者取走使用,消费者从缓冲器取出产品去消费。
在生产者和消费者同时工作时,必须禁止生产者将产品放入已装满的缓冲器,禁止消费者从空缓冲器取产品。
五、源程序(含注释)清单#include<windows.h>printf("Consumer %2d finish consuming product %2d\n ",m_serial,m_thread_request[i]);}//离开临界区LeaveCriticalSection(&PC_Critical[BufferPos]);}}六、测试结果以及实验总结1、通过实验进一步了解了基本的进程同步与互斥算法,理解生产者-消费者问题2、掌握了相关API的使用方法。
3、了解到进程是一个可以拥有资源的基本单位,是一个可以独立调度和分派的基本单位。
而线程是进程中的一个实体,是被系统独立调度和分配的基本单位,故又称为轻权(轻型)进程(Light Weight Process)。
操作系统实验--进程的同步heu
操作系统实验报告工程大学计算机科学与技术学院页脚.第六讲进程的同步一、实验概述1. 实验名称进程的同步2. 实验目的(1)使用EOS 的信号量编程解决生产者—消费者问题,理解进程同步的意义。
(2)调试跟踪EOS 的信号量的工作过程,理解进程同步的原理。
(3)修改EOS 的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
3. 实验类型验证型实验,设计性实验4. 实验容(1)准备实验(2)使用 EOS 的信号量解决生产者-消费者问题(3)调试 EOS 信号量的工作过程1)创建信号量2)等待释放信号量3)等待信号量(不阻塞)4)释放信号量(不唤醒)5) 等待信号量(阻塞)6) 释放信号量(唤醒)(4)修改 EOS 的信号量算法二、实验环境操作系统集成实验环境OS Lab三、实验过程1. 设计思路和流程图2. 算法实现3. 需要解决的问题及解答(1). P143生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢?答:此时生产了0-13号14个产品,消费了0-3号4个产品,缓冲区都占满了。
只有缓冲区有空闲生产者才能生产东西,有权向里面放东西。
所以它必须等到消费者,取走产品,有空闲缓冲区时,才继续生产14号产品。
(2). P145-3.4 修改EOS的信号量算法(只看一次消费1个产品的,一次消费2个产品的可以写到实验报告中)答:见三,四部分(3). 思考在ps/semaphore.c文件的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作?答:原子操作要求一旦开始就要运行到结束,不能有中断。
在执行等待信号量和释放信号量的时候,不允许cpu响应外部中断,所以使用原子操作。
(4). 绘制ps/semaphore.c文件PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。
北交大操作系统作业-进程同步实验
进程同步实验 (1)实验目的 (1)实验过程 (1)1.制造混乱 (1)实验结果: (3)结果分析: (3)2.mutex 方案 (4)实验结果: (5)结果分析: (6)3.软件方案 (6)实验结果: (9)结果分析: (10)进程同步实验实验目的讨论临界区问题及其解决方案。
实验首先创建两个共享数据资源的并发线程。
在没有同步控制机制的情况下,我们将看到某些异常现象。
针对观察到的现象,本实验采用两套解决方案:•利用Windows 的mutex 机制•采用软件方案然后比较这两种方案的性能优劣。
实验过程1.制造混乱Windows 操作系统支持抢先式调度,这意味着一线程运行一段时间后,操作系统会暂停其运行并启动另一线程。
也就是说,进程内的所有线程会以不可预知的步调并发执行。
为了制造混乱,我们首先创建两个线程t1 和t2。
父线程(主线程)定义两个全局变量,比如accnt1 和accnt2。
每个变量表示一个银行账户,其值表示该账户的存款余额,初始值为0。
线程模拟在两个账户之间进行转账的交易。
也即,每个线程首先读取两个账户的余额,然后产生一个随机数r,在其中一个账户上减去该数,在另一个账户上加上该数。
线程操作的代码如下:#include <stdlib.h>#include <stdio.h>#include <windows.h>int accnt1 = 0;int accnt2 = 0;double begin=0,end=0,time=0;int i=1;DWORD WINAPI run( LPVOID p) {int counter=0;int tmp1, tmp2, r;begin=GetTickCount();do {tmp1 = accnt1;tmp2 = accnt2;r = rand();accnt1 = tmp1 + r;accnt2 = tmp2 - r;counter++;} while ( accnt1 + accnt2 == 0 &&counter<); end=GetTickCount();time=end-begin;printf ("counter=%d\n", counter);printf ("进程%d用时%lf \n", i,time);i++;counter =0;return 0;}int main(int argc, char *argv[]){CreateThread(NULL,0,run,NULL,0,NULL); CreateThread(NULL,0, run,NULL,0,NULL);system("PAUSE");return 0;}实验结果:结果分析:两个线程执行相同的代码。
操作系统进程同步
操作系统进程同步在计算机操作系统中,进程同步是一个至关重要的概念。
它就像是一场精心编排的舞蹈,每个进程都是一位舞者,需要在特定的节奏和规则下协调动作,以确保整个系统的高效、稳定运行。
想象一下,如果多个进程在没有任何协调的情况下随意运行,那会是怎样的混乱场景?就好比一群没有指挥的乐手,各自演奏着自己的旋律,结果只能是刺耳的噪音。
进程同步的目的,就是为了避免这种混乱,让各个进程能够有条不紊地执行任务,充分利用系统资源,提高系统的性能和可靠性。
那么,什么是进程同步呢?简单来说,进程同步是指多个进程在执行过程中,通过某种机制协调它们的执行顺序和访问共享资源的方式,以保证结果的正确性和一致性。
为了更好地理解进程同步,我们先来了解一下进程的概念。
进程是操作系统进行资源分配和调度的基本单位,它可以看作是一个正在执行的程序实例。
每个进程都有自己独立的地址空间、执行上下文和资源需求。
在实际的系统中,进程之间经常需要共享资源,比如内存中的数据、外部设备等。
如果多个进程同时访问和修改这些共享资源,就可能会导致数据不一致、错误甚至系统崩溃等问题。
这就好比两个孩子同时在一块黑板上写字,如果没有规则来约束,他们的笔迹很可能会重叠在一起,变得混乱不堪。
为了解决这些问题,操作系统提供了多种进程同步的机制。
其中,最常见的有信号量、互斥锁、条件变量等。
信号量就像是一个交通信号灯,它控制着进程对共享资源的访问。
信号量有一个整数值,用于表示可用资源的数量。
当一个进程想要访问共享资源时,它需要先获取信号量。
如果信号量的值大于零,进程就可以获取资源并将信号量的值减一;如果信号量的值为零,进程就需要等待,直到其他进程释放资源并将信号量的值增加。
互斥锁则像是一把钥匙,只有拥有这把钥匙的进程才能访问共享资源。
当一个进程获取到互斥锁时,其他进程就无法访问该资源,直到持有锁的进程释放锁。
条件变量则用于实现进程之间的等待和通知机制。
当一个进程等待某个条件满足时,它可以阻塞在条件变量上。
操作系统实训报告进程同步和互斥
进程同步和互斥一、设计目的:通过实现哲学家进餐问题的同步深入了解和掌握进程同步和互斥的原理。
二、设计内容哲学家有N个,也定全体到达后开始讨论:在讨论的间隙哲学家进餐,每人进餐时都需使用刀、叉各一把,所有哲学家刀和叉都拿到后才能进餐。
哲学家的人数、餐桌上的布置自行设定,实现刀和叉的互斥使用算法的程序实现。
三、开发环境windows环境,VC6.0平台。
四、分析设计<一>实验原理不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
每个进程中访问临界资源的那段代码称为临界区(Critical Section)。
每个进程中访问临界资源的那段程序称为临界区(Critical Section)(临界资源是一次仅允许一个进程使用的共享资源)。
每次只准许一个进程进入临界区,进入后不允许其他进程进入。
不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
本程序主要使用了EnterCriticalSection (&cs)和LeaveCriticalSection (&cs)两个函数实现临界区互斥。
EnterCriticalSection (&cs)用来进入临界区,LeaveCriticalSection (&cs)用来离开临界区。
哲学家进餐问题设定图<二>程序结构1、主程序模块(详见图1)2、状态改变模块(详见图2)3、返回哲学家状态模块(详见图3)4、返回餐具状态模块(详见图4)<三>数据结构:程序中定义一个哲学家类,包含两个私有对象和四个公有对象。
Number对象:报讯哲学家的编号。
Status对象:用于保存当前该哲学家的状态,0表示正在等待(即处于饥饿状态)1表示得到餐具正在吃饭,2表示正在思考Philosopher(int num)方法:哲学家类构造函数,参数num表示哲学家编号find() const方法:返回该哲学家编号getinfo() const方法:返回哲学家当前状态Change()方法:根据题目要求改变哲学家的状态(等待->进餐->思考->等待…………)另外,程序中包含一个公有对象,bool类型数组tools[6],用来保存6把餐当前状态:true 表示该餐具当前空闲,false表示该餐具当前正被使用。
北邮大三上-操作系统-进程同步实验报告
操作系统实验二进程同步实验班级:2009211311 学号:姓名:schnee目录1. 实验目的 (2)2. 实验要求 (2)3. 环境说明 (2)4. 实验前期思考 (2)5. 实验知识点储备 (3)5.1.进程 (3)5.2.线程 (3)5.3.同步和互斥 (3)5.4.库函数和类型储备 (4)6. 编程实现: (6)6.1. 调整和框架 (6)6.2. 源程序实现(详细框架见注释) (6)6.3. 实现中遇到过的困难和解决方法 (9)6.4. 运行示例及结果截图 (10)7. 心得和优化 (11)1.实验目的1)理解进程/线程同步的方法,学会运用进程/线程同步的方法解决实际问题;2)了解windows系统或unix/linux系统下中信号量的使用方法。
2.实验要求编写一个有关生产者和消费者的程序:每个生产者每次生产一个产品存入仓库,每个消费者每次从仓库中取出一个产品进行消费,仓库大小有限,每次只能有一个生产者或消费者访问仓库。
要求:采用信号量机制。
3.环境说明此实验采用的是Win7下Code::blocks 10.05编译器,采用Win API的信号量机制编程。
此word实验文档中采用notepad++的语法高亮。
4.实验前期思考可能有多个生产者和消费者。
可以假设输入P表示创建一个生产者线程,输入C表示创建一个消费者线程。
生产者线程等待仓库有空位并且占据此空位,,然后等待仓库的操作权,执行操作,最后释放仓库操作权。
一开始以为是占位的操作在获得操作权后,疑惑:若是等待空位后在等待获得操作权时又没有空位了,岂不是又不能放入了?若是先获得操作权再等空位,则在无空位时会进入无穷等待状态,因为没有人来改变空位个数。
这两个问题如何克服呢?其实第一个疑问是因为我对wait函数的具体操作还有点模糊,实际上wait操作便是一等到空位就顺便占了,而不是我想的等位和占位分离。
而第二个问题自然是不行的,这种操作顺序应该抛弃。
操作系统进程同步与互斥实验报告0204192337
学生实验报告姓名:年级专业班级学号成绩#define N 1 //N定义为临界资源!printf("请输入三个进程:\n"); //初始状态为:临界资源处于空闲状态!loop:scanf("%d %d %d",&a,&b,&c); //输入的进程名为:a,b,c!进程名输入的先后代表进程的访问顺序!if(a==N) //判断进程a是否占据临界资源!若a==N,表明a访问临界资源!{printf("a=%d\n",a); //a正在访问临界资源!printf("b=0,c=0\n"); //b,c不能进入自己的临界区,需等待a释放临界资源!printf(“临界资源正在被进程a访问,进程b,c必须等待.\n”);}else if(b==N){printf("b=%d\n",b); //b正在访问临界资源!printf("a=0,c=0\n"); //a,c不能进入自己的临界区,需等待b释放临界资源!printf(“临界资源正在被进程b访问,进程a,c必须等待.\n”);}5.编译链接所编写的程序,在编译正确的情况下执行程序.6.记录程序执行的结果(如下图所示).注意:初始状态为:临界资源处于空闲状20 10年12 月16 日【实验结果或总结】(对实验结果进行相应分析,或总结实验的心得体会,并提出实验的改进意见)1.进程a,b,c分别访问临界资源时程序执行的结果如下.(a) (b) (c)2.该程序初始化N为临界资源,根据输入a,b,c,的值是否等于N来判断进程分别是否进入自己的临界区。
当a=N 表明进程a正在访问临界资源。
此时程序执行的输出为:a=1,b=c=0表示进程b,c不能进入自己的临界区。
3.该程序能较好地体现程序并发执行时的一种制约关系-互斥,但不能较好的反映进程的同步关系,所以该算法有待改进,用以同时实现进程的同步和互斥。
操作系统进程同步实验报告
操作系统进程同步实验报告本实验旨在通过模拟操作系统中进程的同步问题,加深学生对操作系统中进程同步机制的了解和实践能力。
本次实验分为两个部分,第一个部分是使用信号量实现进程同步,第二个部分是使用管程实现进程同步。
第一部分实验:使用信号量实现进程同步本部分实验的目标是使用信号量来实现进程同步,确保资源的互斥访问。
在Linux系统中,信号量是一种用来控制进程同步的机制,可以用于保证共享资源的互斥访问、避免死锁等问题。
具体实验流程如下:1. 定义一个信号量,用于互斥访问共享资源在Linux系统中,使用semget函数可以创建一个信号量集,使用semctl函数可以对信号量进行控制。
```#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#define KEY 1234 // 定义信号量的键值int semid; // 定义信号量标识符union semun{int val; // 信号量的初始值struct semid_ds *buf; // IPC_STAT, IPC_SET操作时用ushort *array; // GETALL, SETALL操作时用};void init_sem(){int ret;union semun semunion;// 创建信号量semid = semget(KEY, 1, IPC_CREAT | 0666);if(semid == -1){perror("semget error");exit(1);}2. 定义生产者和消费者进程,并使用信号量来实现同步在生产者和消费者进程中,需要先对信号量进行P操作,即申请资源,然后进行对共享资源的操作,最后再对信号量进行V操作,即释放资源。
本实验中,共享资源是一个循环缓冲区,生产者进程向其中写入数据,消费者进程从中读取数据。
北邮-大三-操作系统-进程管理实验报告
北邮-大三-操作系统-进程管理实验报告实验一进程管理1.实验目的:(1)加深对进程概念的理解,明确进程和程序的区别;(2)进一步认识并发执行的实质;(3)分析进程争用资源的现象,学习解决进程互斥的方法;(4)了解Linux系统中进程通信的基本原理。
2.实验预备内容(1)阅读Linux的sched.h源码文件,加深对进程管理概念的理解;(2)阅读Linux的fork()源码文件,分析进程的创建过程。
3.实验内容(1)进程的创建:编写一段程序,使用系统调用fork() 创建两个子进程。
当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:父进程显示字符“a”,子进程分别显示字符“b”和“c”。
试观察记录屏幕上2/323/32printf("b\n");}else{pid2 = fork();if(pid2<0){fprintf(stderr,"childprocess1 failed");exit(-1);}else if(pid2 == 0){printf("c\n");}else{printf("a\n");sleep(2);4/32exit(0);}}return 0;}结果如下:分析原因:pid=fork();操作系统创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的表项。
新进程和原有进程的可执行程序是同一个程序;上下文和数据,绝大部分就是原进程(父进程)的拷贝,但它们是两个相互独立的进程!因此,这三个进程哪个先执行,哪个后执行,完全取决于操作系统的调度,没有固定的顺序。
(2)进程的控制修改已经编写的程序,将每个进程输出一个字符改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。
5/32将父进程的输出改为father process completed输出b的子进程改为输出child process1 completed输出c的子进程改为输出child process2 completed运行的结果如下:理由同(1)如果在程序中使用系统调用lockf () 来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验一进程同步1.实习要求在Windows 环境下,创建一个包含n 个线程的控制进程。
用这n 个线程来表示n个读者或写者。
每个线程按相应测试数据文件的要求,进行读写操作。
请用信号量机制分别实现读者优先和写者优先的读者-写者问题。
读者-写者问题的读写操作限制:1)写-写互斥;2)读-写互斥;3)读-读允许;读者优先的附加限制:如果一个读者申请进行读操作时已有另一读者正在进行读操作,则该读者可直接开始读操作。
写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确信所有处理都遵守相应的读写操作限制。
2.测试数据文件格式测试数据文件包括n 行测试数据,分别描述创建的n 个线程是读者还是写者,以及读写操作的开始时间和持续时间。
每行测试数据包括四个字段,各字段间用空格分隔。
第一字段为一个正整数,表示线程序号。
第一字段表示相应线程角色,R 表示读者是,W 表示写者。
第二字段为一个正数,表示读写操作的开始时间。
线程创建后,延时相应时间(单位为秒)后发出对共享资源的读写申请。
第三字段为一个正数,表示读写操作的持续时间。
当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。
下面是一个测试数据文件的例子:1 R 3 52 W 4 53 R 5 24 R 6 55 W 5.1 33.本实验的相关知识3.1进程进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
3.2线程线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。
一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
由于线程之间的相互制约,致使线程在运行中呈现出间断性。
线程也有就绪、阻塞和运行三种基本状态。
每一个程序都至少有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。
在单个程序中同时运行多个线程完成不同的工作,称为多线程。
3.3 同步和互斥进程互斥是进程之间发生的一种间接性作用,一般是程序不希望的。
通常的情况是两个或两个以上的进程需要同时访问某个共享变量。
我们一般将发生能够问共享变量的程序段成为临界区。
两个进程不能同时进入临界区,否则就会导致数据的不一致,产生与时间有关的错误。
解决互斥问题应该满足互斥和公平两个原则,即任意时刻只能允许一个进程处于同一共享变量的临界区,而且不能让任一进程无限期地等待。
互斥问题可以用硬件方法解决;也可以用软件方法。
同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。
在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。
少数情况是指可以允许多个访问者同时访问资源。
4. 函数4.1 线程控制4.1.1 CreateThread完成线程创建,在调用进程的地址空间上创建一个线程,以执行指定的函数;它的返回值为所创建线程的句柄。
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SDDWORD dwStackSize, // initial stack sizeLPTHREAD_START_ROUTINE lpStartAddress, // threadfunctionLPVOID lpParameter, // thread argumentDWORD dwCreationFlags, // creation optionLPDWORD lpThreadId // thread identifier);4.1.2 ExitThread用于结束当前线程。
VOID ExitThread(DWORD dwExitCode // exit code for this thread);4.1.3 Sleep可在指定的时间内挂起当前线程。
VOID Sleep(DWORD dwMilliseconds // sleep time);4.1.4 信号量控制:CreateMutex创建一个互斥对象,返回对象句柄;HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, // SD BOOL bInitialOwner, // initial ownerLPCTSTR lpName // object name);4.1.5 OpenMutex打开并返回一个已存在的互斥对象句柄,用于后续访问;HANDLE OpenMutex(DWORD dwDesiredAccess, // accessBOOL bInheritHandle, // inheritance option LPCTSTR lpName // object name);4.1.6 ReleaseMutex释放对互斥对象的占用,使之成为可用。
BOOL ReleaseMutex(HANDLE hMutex // handle to mutex);4.1.7 WaitForSingleObject可在指定的时间内等待指定对象为可用状态;DWORD WaitForSingleObject(HANDLE hHandle, // handle to objectDWORD dwMilliseconds // time-out interval);4.2 程序分析4.2.1 读者优先模式:读者进程:RP_ReaderThread()P(mutex);read_count++;if(read_count==1)//如果有读者开始读操作,则停止写操作P(&RP_Write);V(mutex);-----------------------------------------------------读临界区……-----------------------------------------------------P(mutex);read_count--;if(read_count==0)//所有读者读操作完毕,开放写操作V(&RP_Write);V(mutex);写者进程:RP_WriterThread函数的实现如下:P(&RP_Write);---------------------------------------------写临界区……---------------------------------------------V(&RP_Write);4.2.2 写者优先模式:读者进程:WP_ReaderThread()P(mutex1);P(&cs_Read);P(mutex2);read_count++;if(read_count==1)//有读者开始读操作,写者等待P(&cs_Write);V(mutex2);V(&cs_Read);V(mutex1);--------------------------------------读临界区……--------------------------------------P(mutex2);read_count--;if(read_count==0)//所有读者完成读操作,开放写操作V(&cs_Write);V(mutex2);写者进程:WP_WriterThread()P(mutex3);write_count++;if(write_count==1)//有写者要进行操作,之后的读者全部暂停,直到写者完成操作P(&cs_Read);V(mutex3);P(&cs_Write);----------------------------------写临界区……----------------------------------V(&cs_Write);P(mutex3);write_count--;if(write_count==0)//所有写者完成操作,开放读者读操作V(&cs_Read);V(mutex3);4.3 代码头文件#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);//P操作//读者数目增加readcount++;if(readcount==1){//读第一个读者,等待资源EnterCriticalSection(&RP_Write);}ReleaseMutex(h_Mutex);//V操作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);//P操作//读者数目减少readcount--;if(readcount==0){//如果读者全部读完,唤醒写者LeaveCriticalSection(&RP_Write);}ReleaseMutex(h_Mutex);//V操作}//读者优先-写者线程//写者线程信息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;//线程IDDWORD 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;//初始化readcountInitializeCriticalSection(&RP_Write);//初始化临界区ifstream inFile;inFile.open(file);//打开文件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);//P操作//进入读者临界区EnterCriticalSection(&cs_Read);//P操作//阻塞互斥对象mutex2,保证对readcount的访问、修改互斥wait_for_mutex2=WaitForSingleObject(h_mutex2,-1);//P操作//修改读者数目readcount++;if(readcount==1){//如果是第一个读者,等待写者写完EnterCriticalSection(&cs_Write);}ReleaseMutex(h_mutex2);//V操作//让其他读者进入临界区LeaveCriticalSection(&cs_Read);ReleaseMutex(h_mutex1);//V操作//读文件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);//P操作readcount--;if(readcount==0){//如果所有读者读完,唤醒写者LeaveCriticalSection(&cs_Write);}ReleaseMutex(h_mutex2);//V操作}//写者优先--写者线程//p:写者线程信息void WP_WriterThread(void* p){DWORD wait_for_mutex3;DWORD m_delay;//延迟时间DWORD m_persist;//写文件持续时间int m_serial;//线程序号//互斥对象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);//P操作//修改写者数目writecount++;if(writecount==1){//第一个写者,等待读者读完EnterCriticalSection(&cs_Read);}ReleaseMutex(h_mutex3);//V操作//进入写者临界区EnterCriticalSection(&cs_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(&cs_Write);//阻塞互斥对象mutex3,保证对writecount的访问、修改互斥wait_for_mutex3=WaitForSingleObject(h_mutex3,-1);//P操作writecount--;if(writecount==0){//写者写完,读者可以读LeaveCriticalSection(&cs_Read);}ReleaseMutex(h_mutex3);//V操作}//写者优先处理函数//file:文件名void WriterPriority(char* file){DWORD n_thread=0;//线程数目DWORD thread_ID;//线程IDDWORD 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;//初始化readcountwritecount=0;//初始化writecountInitializeCriticalSection(&cs_Write);//初始化临界区InitializeCriticalSection(&cs_Read);ifstream inFile;inFile.open(file);//打开文件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_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");}//主函数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 to Windows \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,写者优先elseWriterPriority("thread.dat");//结束printf("\nPress Any Key To Continue:");_getch();system("cls");}return 0;}5.实验结果输入1:输入2:。