实验二线程与同步 nachos02.docx

上传人:b****5 文档编号:5798306 上传时间:2023-01-01 格式:DOCX 页数:19 大小:235.11KB
下载 相关 举报
实验二线程与同步 nachos02.docx_第1页
第1页 / 共19页
实验二线程与同步 nachos02.docx_第2页
第2页 / 共19页
实验二线程与同步 nachos02.docx_第3页
第3页 / 共19页
实验二线程与同步 nachos02.docx_第4页
第4页 / 共19页
实验二线程与同步 nachos02.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

实验二线程与同步 nachos02.docx

《实验二线程与同步 nachos02.docx》由会员分享,可在线阅读,更多相关《实验二线程与同步 nachos02.docx(19页珍藏版)》请在冰豆网上搜索。

实验二线程与同步 nachos02.docx

实验二线程与同步nachos02

实验报告

2302010220不可不戒

一、实验目的

实现Nachos的同步机制:

锁和条件变量,并利用这些同步机制实现几个基础工具类

二.实验内容&设计思想&代码

首先根据老师提供的文档,对必要的文件进行了理解后进行实验

1.实现锁机制和条件变量,并利用这些同步机制将实验一中所实现双向有序链表类修改成线程安全的

A.使用Thread:

:

Sleep实现锁机制和条件变量

在每一个函数(操作)开始时先开中断,结束后在关中断。

1.锁Lock

Acquire()

申请锁

当锁lockValue=false,说明锁不可用,当前线程进入睡眠状态。

当锁lockValue=true,说明锁可用,当前线程获得该锁,继续运行。

VoidLock:

:

Acquire()

{

//ASSERT(!

isHeldByCurrentThread());

IntStatusoldLevel=interrupt->SetLevel(IntOff);

while(lockValue)//locknotavailable

{

queue->Append((void*)currentThread);

currentThread->Sleep();

}

lockValue=true;//lockavailable

owner=currentThread;//recordthenewownerofthelock

(void)interrupt->SetLevel(oldLevel);

}

Release()

释放锁(注意:

只有拥有锁的线程才能释放锁)

lockValue=true

如果有其它线程等待该锁,将其中的一个唤醒,进入就绪态。

boolisHeldByCurrentThread()用于判定当前进程是否是锁的持有者。

voidLock:

:

Release()

{

Thread*thread;

ASSERT(isHeldByCurrentThread());

IntStatusoldLevel=interrupt->SetLevel(IntOff);

thread=(Thread*)queue->Remove();

if(thread!

=NULL)

scheduler->ReadyToRun(thread);

lockValue=false;

owner=NULL;

(void)interrupt->SetLevel(oldLevel);

}

2.条件变量Condition

Wait、Signal以及BroadCast,所有的这些操作必须在当前线程获得一个锁的前提下而且所有对一个条件变量进行的操作必须建立在同一个锁的前提下

Wait()

线程等待条件变量

释放该锁

进入睡眠状态

重新申请该锁

voidCondition:

:

Wait(Lock*conditionLock)

{

ASSERT(conditionLock->isHeldByCurrentThread());

IntStatusoldLevel=interrupt->SetLevel(IntOff);

conditionLock->Release();

queue->Append((void*)currentThread);

currentThread->Sleep();

conditionLock->Acquire();

(void)interrupt->SetLevel(oldLevel);

}

Signal()

唤醒一个等待该条件变量的线程(如果存在的话)

voidCondition:

:

Signal(Lock*conditionLock)

{

Thread*thread;

ASSERT(conditionLock->isHeldByCurrentThread());

IntStatusoldLevel=interrupt->SetLevel(IntOff);

thread=(Thread*)queue->Remove();

if(thread!

=NULL)

scheduler->ReadyToRun(thread);

(void)interrupt->SetLevel(oldLevel);

//makethreadready,comsumingtheVimmediately

}

BroadCast()

唤醒所有等待该条件变量的线程(如果存在的话)

voidCondition:

:

Broadcast(Lock*conditionLock)

{

Thread*thread;

ASSERT(conditionLock->isHeldByCurrentThread());

IntStatusoldLevel=interrupt->SetLevel(IntOff);

thread=(Thread*)queue->Remove();

while(thread!

=NULL)

{

scheduler->ReadyToRun(thread);

thread=(Thread*)queue->Remove();

}

(void)interrupt->SetLevel(oldLevel);

}

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实现锁机制和条件变量。

voidLock:

:

Acquire()

{

sem_lock->P();

owner=currentThread;

}

voidLock:

:

Release()

{

ASSERT(isHeldByCurrentThread());

owner=NULL;

sem_lock->V();

}

voidCondition:

:

Wait(Lock*conditionLock)

{

ASSERT(conditionLock->isHeldByCurrentThread());

conditionLock->Release();

wait_count_thread++;

sem_condition->P();

conditionLock->Acquire();

}

voidCondition:

:

Signal(Lock*conditionLock)

{

ASSERT(conditionLock->isHeldByCurrentThread());

if(wait_count_thread>0)

{

sem_condition->V();

wait_count_thread--;

}

if(wait_count_thread<0)

wait_count_thread=0;

}

//wakeupallthesleepthreads

voidCondition:

:

Broadcast(Lock*conditionLock)

{

ASSERT(conditionLock->isHeldByCurrentThread());

while(wait_count_thread--)

sem_condition->V();

if(wait_count_thread<0)

wait_count_thread=0;

}

 

C.用锁机制和条件变量修改双向有序链表

1.基本同实验一。

2.分别对void*DLList:

:

Remove(int*keyPtr)和voidDLList:

:

SortedInsert(void*item,intsortKey)这两个函数做了加锁的处理。

Lock&Condition实现方法:

sleep+中断禁止与启用

...............

...............

void*DLList:

:

Remove(int*keyPtr)

{

if(flag)

sleep_lock->Acquire();

......

if(flag)

while(IsEmpty())//dllistisempty

sleep_condition->Wait(sleep_lock);//wait

elseif(IsEmpty())

returnNULL;

........

if(err_type==4)

{

//printf("Removeerror\n");

currentThread->Yield();

}

........

if(flag)

sleep_lock->Release();}

..............................

2.实现一个线程安全的表结构

A.在头文件synch.h中加入boollockValue标记锁是否可用;Thread*owner用于判定锁是否为当前线程所有;

B.在初始化table时要创建新的lock锁变量,在析构函数中将其删除即可

C.要实现线程安全关键是Alloc函数与get函数,在执行时要加入锁机制,以免被线程中断二导致错误。

Alloc要求往Table中加入Object,如果满了则返回-1

intTable:

:

Alloc(char*obj)

{

if(flag==1)

tableLock->Acquire();

for(inti=0;i

{

if(table[i]==NULL)

{

//currentThread->Yield();

table[i]=obj;

if(flag==1)

tableLock->Release();

returni;

}

}

if(flag==1)

tableLock->Release();

return-1;

}

Release()函数是从Table中删除table[index]

voidTable:

:

Release(intindex,intwhich,inti)

{

if(flag==1)

tableLock->Acquire();

if(index>=0&&index

{

if(*table[index]!

=NULL)

{

printf("table[%d]=%cisReleasedbythread%di=%d\n",index,*table[index],which,i);

table[index]=NULL;//删除后,地址赋值NULL

}

else

printf("table[%d]isNULLbythread%di=%d\n",index,which,i);

}

else

printf("table[%d]isNULLbythread%di=%d\n",index,which,i);

if(flag==1)

tableLock->Release();

}

3.实现一个大小受限的缓冲区

A.主要设计思想参考课本5.3.2节——生产者/消费者问题。

B.三个不同信号量的初始化

n=newSemaphore("used",1);//缓冲区中的项数

s=newSemaphore("sem",0);//用于实施互斥

e=newSemaphore("empty",maxsize);//空闲空间的数目

C.Buffer实现方法semaphone&使用Semaphore实现锁机制和条件变量

注:

semaphone见代码注释

1.Read()从缓存区读取

voidBoundedBuffer:

:

Read(void*data,intsize)

{

int*r=(int*)data;

while(size--)

{

if(flag==1)

{//若readout==writein:

缓冲区没有可读数据

sem_Lock->Acquire();

while(writein==readout)

{

//printf("waitr%d\n",size);

bufferEmpty->Wait(sem_Lock);

//n->P();

}

//s->P();

}

*r++=Buffer[readout];

readout=(readout+1)%Buffersize;

if(flag==1)

{

bufferFull->Broadcast(sem_Lock);//bufferisnotfull,wakeupwaitwritingthreads

sem_Lock->Release();

//s->V();

//e->V();

}

}

}

2.Write()函数向缓存区写入数据

voidBoundedBuffer:

:

Write(void*data,intsize)

{

int*w=(int*)data;

while(size--)

{

if(flag==1)

{//若(writein+1)%Buffersize==readout:

缓冲区满。

注意:

这里有一个空间未被使用

sem_Lock->Acquire();

while((writein+1)%Buffersize==readout)

{

//printf("waitw%d\n",size);

bufferFull->Wait(sem_Lock);

//e->P();

}

//s->P();

}

Buffer[writein]=*w++;

writein=(writein+1)%Buffersize;

if(flag==1)

{

bufferEmpty->Broadcast(sem_Lock);//bufferisnotempty,wakeupwaitwritingthreads

sem_Lock->Release();

//s->V();

//n->V();

}

}

}//每次写入1bytes,就有可能线程切换.读取就会乱序

 

4.关于测试

代码见threadtest.cc

二、实验结果

相关参数说明:

-rscausesYieldtooccuratrandom(butrepeatable)spots

修改system.ccvoidInitalize(intargc,char**argv)bool=randomYield=TRUE

1.dllist.cc测试结果Lock&Condition实现方法:

sleep+中断禁止与启用

./nachos-q2-t2-n5-e0-rs2flag=1使用锁机制e=0没有错误

./nachos-q2-t2-n5-e0-rs2flag=0不使用锁机制e=0没有错误

./nachos-q2-t2-n5-e0-rs2flag=1使用锁机制e=4有错误

./nachos-q2-t2-n5-e0-rs2flag=0不用锁机制e=4有错误

Dllist.cc测试使用Semaphore实现锁机制和条件变量

./nachos-q2-t2-n5-e4flag=0不使用锁

./nachos-q2-t2-n5-e4flag=1使用锁

2.Table测试结果

./nachos-q3-t2-rs2flag=1使用锁机制结果没问题

./nachos-q3-t2-rs2falg=0不使用锁结果出现错误

3.BoundedBuffer测试结果实现方法semaphone

./nachos-q4-t5-rs3flag=1使用信号量

./nachos-q4-t5-rs3flag=0不使用信号量

让每一个线程往缓存区写入当前线程号:

实现方法lock&condition

三、实验中遇到的问题&总结

问题:

1.开始线程不能随机切换,(-rs在助教的帮助下解决)

解决:

删除nachos-3.4,重新编译。

2.在链表加锁时,一开始忘记对链表为空的情况进行判定,出现了错误

解决:

在链表中对有可能因为链表为空的情况加入判断,如果出现空则调用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