您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 南昌大学操作系统实验报告
1实验报告实验课程:计算机操作系统学生姓名:郭慧学号:6100512019专业班级:电子商务121班2014年5月30日2目录一、实验一………………………………………………………03二、实验二………………………………………………………12三、实验三………………………………………………………19南昌大学实验报告学生姓名:郭慧学号:6100512019专业班级:电子商务121班实验类型:□验证□综合□设计□创新实验日期:2014-5-16实验成绩:3实验1进程/线程同步一、实验目的本实验讨论临界区问题及其解决方案。首先创建两个共享数据资源的并发线程。在没有同步控制机制的情况下,我们将看到某些异常现象。针对观察到的现象,本实验采用两套解决方案:•利用Windows的mutex机制•采用软件方案然后比较这两种方案的性能优劣。二、实验内容2.1进程/线程并发执行Windows操作系统支持抢先式调度,这意味着一线程运行一段时间后,操作系统会暂停其运行并启动另一线程。也就是说,进程内的所有线程会以不可预知的步调并发执行。为了制造混乱,我们首先创建两个线程t1和t2。父线程(主线程)定义两个全局变量,比如accnt1和accnt2。每个变量表示一个银行账户,其值表示该账户的存款余额,初始值为0。线程模拟在两个账户之间进行转账的交易。也即,每个线程首先读取两个账户的余额,然后产生一个随机数r,在其中一个账户上减去该数,在另一个账户上加上该数。线程操作的代码框架如下:counter=0;do{tmp1=accnt1;tmp2=accnt2;r=rand();accnt1=tmp1+r;accnt2=tmp2−r;counter++;}while(accnt1+accnt2==0);print(counter);两个线程执行相同的代码。只要它们的执行过程不相互交叉,那么两个账户的余额之和将永远是0。但如果发生了交叉,那么某线程就有可能读到新的accnt1值和老的accnt2值,从而导致账户余额数据发生混乱。线程一旦检测到混乱的发生,便终止循环并打印交易的次数(counter)。请编写出完整的程序代码并运行,然后观察产生混乱需要的时间长短。因为这是我们编写的第一个程序,因此这里我给出了完整的代码,请参考。有能力的同学在参考下面的代码之前,请先自己尝试一下。#includestdio.h#includestdlib.h#includewindows.hintaccnt1=0;intaccnt2=0;DWORDWINAPIrun(LPVOIDp){intcounter=0;inttmp1,tmp2,r;do{tmp1=accnt1;tmp2=accnt2;r=rand();4accnt1=tmp1+r;accnt2=tmp2−r;counter++;}while(accnt1+accnt2==0);printf(”%d\n”,counter);}intmain(intargc,char∗argv[]){CreateThread(NULL,0,run,NULL,0,NULL);CreateThread(NULL,0,run,NULL,0,NULL);system(“PAUSE”);return0;}反复运行该程序。请问,观察到了什么?你能解释这些现象吗?2.2临界区问题之解决方案上面例子中,线程执行的代码叫做临界区,因为两个线程在这里访问了同样的数据,在没有保护的情况下,有可能发生混乱。解决该问题有两套方案。其一,如果操作系统提供了同步原语,例如mutex,那么就可直接利用该原语对临界区进行排它性的存取保护。其二,如果操作系统不提供这样的原语,那么可用软件方案加以解决。本实验中,我们将实现并比较这两种方案。2.2.1mutex方案Windows操作系统提供了mutex对象。mutex状态可以是signaled(unlocked)或者是nonsignaled(locked)。利用mutex对象,可以方便地实现临界区保护。进入临界区时(在第一个读操作之前),锁住mutex对象;离开临界区时(在第二个写操作之后),打开mutex对象。线程的阻塞与唤醒由系统管理,程序员无需干预。以下给出的是在Windows操作系统下有关mutex对象操作的提示。创建一个未上锁mutex对象的代码如下:HANDLEhMutex=CreateMutex(NULL,FALSE,NULL);给mutex对象上锁的代码如下:WaitForSingleObject(hMutex,INFINITE);打开mutex对象的代码如下:ReleaseMutex(hMutex);5根据以上提示,编写出用mutex对象保护临界区的解决方案。完成后,请思考以下问题:假设把加锁和开锁操作分别放置在第一个写操作之前和第二个写操作之后,能否实现临界区的保护,为什么?2.2.2软件方案现在假设操作系统没有提供同步原语。这时,我们只能通过编程语言对变量的操作实现临界区保护。下面给出的是一个概念性的解决方案框架:intc1=0,c2=0,willwait;cobeginp1:while(1){c1=1;willwait=1;while(c2&&(willwait==1));/∗waitloop∗/CS1;c1=0;program1;}p2:while(1){c2=1;willwait=2;while(c1&&(willwait==2));/∗waitloop∗/CS2;c2=0;program2;}上面的方案使用了三个变量c1,c2和willwait。线程i试图进入临界区时首先把变量ci置为1,接着把变量willwait的值设置为i(为什么?)阻塞通过临界区之前的循环实现。当线程退出临界区时,又把变量ci的值设置为0。在我们的例子中,临界区始于第一个读操作,结束于第二个写操作。请把上面的概念框架转换为可运行的C代码,实现临界区的保护。为了加快程序的执行速度,可在阻塞循环中增加一个Sleep(0)语句。这可以让不能进入临界区的线程马上放弃处理器,而不用无谓消耗处理器资源。最后,请比较mutex方案和软件方案的效率(执行相同的循环次数,计算消耗的时间。为了让结果更科学,请多次试验,然后计算平均值)。提示:时间度量可以用DWORDGetTickCount(VOID)在操作开始之前调用一次,操作结束之后再调用一次,两次调用所得到的返回值的差便是该操作所消耗的大致时间(单位毫秒)。三、实验代码、数据及处理结果2.1进程/线程并发执行#includestdafx.hint_tmain(intargc,_TCHAR*argv[]){return0;}#includestdio.h6#includestdlib.h#includewindows.hintaccnt1=0;intaccnt2=0;DWORDWINAPIrun(LPVOIDp){intcounter=0;inttmp1,tmp2,r;do{tmp1=accnt1;tmp2=accnt2;r=rand();accnt1=tmp1+r;accnt2=tmp2-r;counter++;}while(accnt1+accnt2==0);printf(循环1次数为%d\n,counter);printf(%d,%d\n\n,accnt1,accnt2);return0;}intmain(intargc,char∗argv[]){CreateThread(NULL,0,run,NULL,0,NULL);CreateThread(NULL,0,run,NULL,0,NULL);system(PAUSE);return0;}7由运行结果可观察出,当没有任何线程同步机制时,程序无法循环多次。原因是没有线程同步机制。2.21mutex方案#includestdafx.hint_tmain(intargc,_TCHAR*argv[]){return0;}#includestdio.h#includestdlib.h#includewindows.hintaccnt1=0;intaccnt2=0;doublebegin=0;doubleend=0;doubletime=0;inta=1;HANDLEhMutex=CreateMutex(NULL,FALSE,NULL);DWORDWINAPIrun(LPVOIDp){intcounter=0;inttmp1,tmp2,r;do{tmp1=accnt1;tmp2=accnt2;r=rand();accnt1=tmp1+r;accnt2=tmp2-r;counter++;}while(accnt1+accnt2==0&&counter1000000);printf(循环%d次数为%d\n,a,counter);printf(%d,%d\n\n,accnt1,accnt2);end=GetTickCount();time=end-begin;printf(进程%d所用时间为%d\n,a,time);a++;ReleaseMutex(hMutex);counter=0;return0;}intmain(intargc,char∗argv[]){CreateThread(NULL,0,run,NULL,0,NULL);CreateThread(NULL,0,run,NULL,0,NULL);system(PAUSE);return0;8}由运行结果可观察出,当采用mutex方法时,两进程所运行的时间大致是相同的,进程运行完全,有效地防止了两进程相互交叉以及障碍。2.22#includestdafx.hint_tmain(intargc,_TCHAR*argv[]){return0;}#includestdio.h#includestdlib.h#includewindows.hintaccnt1=0;intaccnt2=0;DWORDWINAPIrun1(LPVOIDp){intcounter=0;inttmp1,tmp2,r;doublebegin=0,end=0,time=0;begin=GetTickCount();9do{tmp1=accnt1;tmp2=accnt2;r=rand();accnt1=tmp1+r;accnt2=tmp2-r;counter++;}while(accnt1+accnt2==0&&counter1000000);printf(循环次数为%d\n,counter);printf(%d,%d\n\n,accnt1,accnt2);end=GetTickCount();time=end-begin;printf(进程1所用时间为%d\n,time);counter=0;return0;}DWORDWINAPIrun2(LPVOIDp){intcounter=0;inttmp1,tmp2,r;doublebegin=0,end=0,time=0;begin=GetTickCount();do{tmp1=accnt1;tmp2=accnt2;r=rand();accnt1=tmp1+r;accnt2=tmp2-r;counter++;}while(accnt1+accnt2==0&&counter1000000);printf(循环次数为%d\n,counter);printf(%d,%d\n\n,accnt1,accnt2);end=GetTickCount();time=end-begin;printf(进程2所用时间为%d\n,time);counter=0;return0;}intmain(intargc,char∗argv[]){boolc1=false,c2=false;intwillwait;while(1);{c1=true;10willwait=1;while(c1&&(willwait=1)){CreateThread(NULL,0,r
本文标题:南昌大学操作系统实验报告
链接地址:https://www.777doc.com/doc-4209321 .html