1、实验二线程与同步 nachos02实验报告 2302010220不可不戒一、实验目的实现Nachos的同步机制:锁和条件变量,并利用这些同步机制实现几个基础工具类二实验内容&设计思想&代码首先根据老师提供的文档,对必要的文件进行了理解后进行实验1.实现锁机制和条件变量,并利用这些同步机制将实验一中所实现双向有序链表类修改成线程安全的A使用Thread:Sleep实现锁机制和条件变量在每一个函数(操作)开始时先开中断,结束后在关中断。1.锁LockAcquire()申请锁当锁lockValue=false,说明锁不可用,当前线程进入睡眠状态。当锁lockValue=true,说明锁可用,当前线程
2、获得该锁,继续运行。 Void Lock:Acquire() /ASSERT(!isHeldByCurrentThread(); IntStatus oldLevel=interrupt-SetLevel(IntOff); while(lockValue)/lock not available queue-Append(void *)currentThread); currentThread-Sleep(); lockValue=true;/lock available owner=currentThread;/record the new owner of the lock (void) i
3、nterrupt-SetLevel(oldLevel);Release() 释放锁(注意:只有拥有锁的线程才能释放锁) lockValue=true 如果有其它线程等待该锁,将其中的一个唤醒,进入就绪态。 bool isHeldByCurrentThread()用于判定当前进程是否是锁的持有者。 void Lock:Release() Thread *thread; ASSERT(isHeldByCurrentThread(); IntStatus oldLevel=interrupt-SetLevel(IntOff); thread=(Thread *)queue-Remove(); if(
4、thread !=NULL) scheduler-ReadyToRun(thread); lockValue=false; owner=NULL; (void) interrupt-SetLevel(oldLevel); 2. 条件变量ConditionWait、Signal以及BroadCast,所有的这些操作必须在当前线程获得一个锁的前提下而且所有对一个条件变量进行的操作必须建立在同一个锁的前提下Wait() 线程等待条件变量 释放该锁 进入睡眠状态 重新申请该锁 void Condition:Wait(Lock* conditionLock) ASSERT(conditionLock-i
5、sHeldByCurrentThread(); IntStatus oldLevel=interrupt-SetLevel(IntOff); conditionLock-Release(); queue-Append(void *)currentThread); currentThread-Sleep(); conditionLock-Acquire(); (void)interrupt-SetLevel(oldLevel); Signal() 唤醒一个等待该条件变量的线程(如果存在的话) void Condition:Signal(Lock* conditionLock) Thread *t
6、hread; ASSERT(conditionLock-isHeldByCurrentThread(); IntStatus oldLevel=interrupt-SetLevel(IntOff); thread=(Thread *)queue-Remove(); if(thread !=NULL) scheduler-ReadyToRun(thread); (void)interrupt-SetLevel(oldLevel); /make thread ready,comsuming the V immediately BroadCast() 唤醒所有等待该条件变量的线程(如果存在的话) v
7、oid Condition:Broadcast(Lock* conditionLock) Thread *thread; ASSERT(conditionLock-isHeldByCurrentThread(); IntStatus oldLevel=interrupt-SetLevel(IntOff); thread=(Thread *)queue-Remove(); while(thread !=NULL) scheduler-ReadyToRun(thread); thread=(Thread *)queue-Remove(); (void)interrupt-SetLevel(oldL
8、evel); B使用Semaphore实现锁机制和条件变量1.不需要自行考虑关中断和阻塞队列维护等问题2.Semaphore与条件变量的区别:A.如果在调用Semaphore:P()前调用Semaphore:V() 则V操作的效果将积累下来B.而如果在调用Condition:Wait()前调用Condition:Signal()则Signal操作的效果将不积累3.锁机制直接调用P和V操作,条件变量类似使用Thread:Sleep实现4.在头文件中加入了指向Semaphore变量的指针,用于实现Semaphore实现锁机制和条件变量。void Lock:Acquire() sem_lock-P(
9、); owner=currentThread;void Lock:Release() ASSERT(isHeldByCurrentThread(); owner=NULL; sem_lock-V();void Condition:Wait(Lock* conditionLock) ASSERT(conditionLock-isHeldByCurrentThread(); conditionLock-Release(); wait_count_thread+; sem_condition-P(); conditionLock-Acquire();void Condition:Signal(Loc
10、k* conditionLock) ASSERT(conditionLock-isHeldByCurrentThread(); if(wait_count_thread0) sem_condition-V(); wait_count_thread-; if(wait_count_threadisHeldByCurrentThread(); while(wait_count_thread-) sem_condition-V(); if(wait_count_thread Acquire(); . if(flag) while (IsEmpty()/dllist is empty sleep_co
11、ndition-Wait(sleep_lock);/wait else if(IsEmpty() return NULL; . if(err_type=4) / printf(Remove errorn); currentThread-Yield(); . if(flag) sleep_lock-Release(); .2.实现一个线程安全的表结构A在头文件synch.h中加入bool lockValue标记锁是否可用;Thread *owner用于判定锁是否为当前线程所有;B在初始化table时要创建新的lock锁变量,在析构函数中将其删除即可C要实现线程安全关键是Alloc函数与get函数
12、,在执行时要加入锁机制,以免被线程中断二导致错误。Alloc要求往Table中加入Object,如果满了则返回-1int Table:Alloc(char *obj) if(flag=1) tableLock-Acquire(); for(int i=0;iYield(); tablei=obj; if(flag=1) tableLock-Release(); return i; if(flag=1) tableLock-Release(); return -1;Release()函数是从Table中删除tableindexvoid Table:Release(int index,int wh
13、ich,int i) if(flag=1) tableLock-Acquire(); if(index=0 & indexRelease();3.实现一个大小受限的缓冲区A主要设计思想参考课本5.3.2节生产者/消费者问题。B.三个不同信号量的初始化 n=new Semaphore(used,1);/缓冲区中的项数 s=new Semaphore(sem,0);/用于实施互斥e=new Semaphore(empty,maxsize);/空闲空间的数目C.Buffer 实现方法 semaphone & 使用Semaphore实现锁机制和条件变量注:semaphone见代码注释1.Read()从
14、缓存区读取 void BoundedBuffer:Read(void *data,int size) int *r=(int *)data; while(size-) if(flag=1) /若readout=writein:缓冲区没有可读数据 sem_Lock-Acquire(); while(writein=readout) /printf(wait r%dn,size); bufferEmpty-Wait(sem_Lock); / n-P(); / s-P(); *r+=Bufferreadout; readout=(readout+1)%Buffersize; if(flag=1) b
15、ufferFull-Broadcast(sem_Lock);/buffer is not full,wake up wait writing threads sem_Lock-Release(); / s-V(); / e-V(); 2.Write()函数向缓存区写入数据void BoundedBuffer:Write(void *data,int size) int *w=(int *)data; while(size-) if(flag=1) / 若(writein+1)%Buffersize = readout:缓冲区满。注意:这里有一个空间未被使用 sem_Lock-Acquire()
16、; while(writein+1)%Buffersize=readout) / printf(wait w%dn,size); bufferFull-Wait(sem_Lock); / e-P(); / s-P(); Bufferwritein=*w+; writein=(writein+1)%Buffersize; if(flag=1) bufferEmpty-Broadcast(sem_Lock);/buffer is not empty,wake up wait writing threads sem_Lock-Release(); / s-V(); / n-V(); /每次写入1by
17、tes,就有可能线程切换.读取就会乱序4.关于测试 代码见threadtest.cc二、实验结果相关参数说明:-rs causes Yield to occur at random(but repeatable)spots 修改system.cc void Initalize(int argc,char *argv) bool=randomYield=TRUE1.dllist.cc测试结果 Lock & Condition 实现方法:sleep+中断禁止与启用./nachos -q 2 -t 2 -n 5 -e 0 -rs 2 flag=1 使用锁机制 e=0 没有错误./nachos -q
18、2 -t 2 -n 5 -e 0 -rs 2 flag=0 不使用锁机制e=0 没有错误./nachos -q 2 -t 2 -n 5 -e 0 -rs 2 flag=1 使用锁机制 e=4 有错误./nachos -q 2 -t 2 -n 5 -e 0 -rs 2 flag=0 不用锁机制 e=4 有错误 Dllist.cc 测试 使用Semaphore实现锁机制和条件变量./nachos -q 2 -t 2 -n 5 -e 4 flag=0 不使用锁./nachos -q 2 -t 2 -n 5 -e 4 flag=1 使用锁2.Table测试结果./nachos -q 3 -t 2 -r
19、s 2 flag=1 使用锁机制 结果没问题./nachos -q 3 -t 2 -rs 2 falg=0 不使用锁 结果出现错误 3.BoundedBuffer测试结果 实现方法semaphone./nachos -q 4 -t 5 -rs 3 flag=1 使用信号量./nachos -q 4 -t 5 -rs 3 flag=0 不使用信号量让每一个线程往缓存区写入当前线程号:实现方法 lock & condition三、实验中遇到的问题&总结问题:1. 开始线程不能随机切换,(-rs在助教的帮助下解决) 解决:删除nachos-3.4,重新编译。2. 在链表加锁时,一开始忘记对链表为空的
20、情况进行判定,出现了错误解决:在链表中对有可能因为链表为空的情况加入判断,如果出现空则调用Wait等待。在插入线程执行完以后待用Signal唤醒的等待的进程。3. 在对Table进行操作时,定义了多线程共享table_arr数组,结果一直出错,原来多线程共享全局变量的值会被修改,解决:定义局部变量table_arr数组。4. 在Broadcast 唤醒等待的线程,while()循环后wait_count_thread可能小于0, 当小于0时没赋值0,出现睡死情况。 解决:while()结束判断wait_count_thread是否小于0 ,小于0赋值为0.5. 总结:通过本次实验让我们对信号量的工作机制有了更加深入的理解,可以从线程的观点来考察不同信号量对线程的影响,了解了操作系统对线程并发性的处理过程,对操作系统的架构有了了解。实验分工:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1