操作系统实验nachos01.docx
《操作系统实验nachos01.docx》由会员分享,可在线阅读,更多相关《操作系统实验nachos01.docx(17页珍藏版)》请在冰豆网上搜索。
操作系统实验nachos01
实验一体验Nachos下的并发程序设计
一、实验人员:
二、实验目的:
对nachos进行熟悉,并初步体验nachos下的并发程序设计
三、实验容:
1、安装Nachos
2、用C++实现双向有序链表;
3、在nachos系统中使用所写的链表程序并演示一些并发错误
四、实验步骤:
1、安装Nachos,具体细则如下
下载code-linux.tar.gz并上传到服务器
建立目录(推荐建立主目录下的nachos)
cd到新建目录中
tarzxvfcode-linux.tar.gz的完整路径
cdnachos-3.4/code
make
2、阅读材料
阅读nachos-3.4/code/Makefile
nachos-3.4/code/Makefile.dep
nachos-3.4/code/Mmon
nachos-3.4/code/threads/Makefile
初步了解各Makefile的构成和相互关系。
阅读nachos-3.4/code/threads/main.cc了解nachos如何开始。
阅读nachos-3.4/code/threads/system.cc的Initialize函数中与debug相关的部分及nachos-3.4/code/threads/utility.cc了解DEBUG的实现与使用,以此进一步熟悉nachos系统。
阅读nachos-3.4/code/threads/threadtest.cc,了解nachos中线程的概念及其运作方式。
3、编写相关的dllist.h,dllist.cc,dllist-driver.cc文件,具体代码如下
dllist.h
classDLLElement{
public:
DLLElement(void*itemPtr,intsortKey);//initializealistelement
DLLElement*next;//nextelementonlist
//NULLifthisisthelast
DLLElement*prev;//previouselementonlist
//NULLifthisisthefirst
intkey;//priority,forasortedlist
void*item;//pointertoitemonthelist
};
classDLList{
public:
DLList();//initializethelist
DLList(inttype);
~DLList();//de-allocatethelist
voidPrepend(void*item);//addtoheadoflist(setkey=min_key-1)
voidAppend(void*item);//addtotailoflist(setkey=max_key+1)
void*Remove(int*keyPtr);//removefromheadoflist
//set*keyPtrtokeyoftheremoveditem
//returnitem(orNULLiflistisempty)
boolIsEmpty();//returntrueiflisthaselements
//routinestoput/getitemson/offlistinorder(sortedbykey)
voidSortedInsert(void*item,intsortKey);
void*SortedRemove(intsortKey);//removefirstitemwithkey==sortKey
//returnNULLifnosuchitemexists
private:
DLLElement*first;//headofthelist,NULLifempty
DLLElement*last;//lastelementofthelist,NULLifempty
interr_type;
};
Dllist.cc
#include"copyright.h"
#include"dllist.h"
#include"system.h"
DLLElement:
:
DLLElement(void*itemPtr,intsortKey)//initializealistelement
{
item=itemPtr;
key=sortKey;
next=NULL;
prev=NULL;
}
DLList:
:
DLList()//initializethelist
{
first=NULL;
last=NULL;
err_type=0;
}
DLList:
:
DLList(inttype)
{
first=NULL;
last=NULL;
err_type=type;
}
DLList:
:
~DLList()//de-allocatethelist
{
while(Remove(NULL)!
=NULL)
;
}
voidDLList:
:
Prepend(void*item)//addtoheadoflist(setkey=min_key-1)
{
DLLElement*elm=newDLLElement(item,0);
if(IsEmpty())
{
first=elm;
last=elm;
}
else
{
elm->key=first->key-1;
elm->next=first;
elm->prev=NULL;
first->prev=elm;
first=elm;
}
}
voidDLList:
:
Append(void*item)//addtotailoflist(setkey=max_key+1)
{
DLLElement*elm=newDLLElement(item,0);
if(IsEmpty())
{
first=elm;
last=elm;
}
else
{
elm->key=last->key+1;
elm->next=NULL;
elm->prev=last;
last->next=elm;
last=elm;
}
}
void*DLList:
:
Remove(int*keyPtr)//removefromheadoflist
{
DLLElement*element;
if(IsEmpty())
{
returnNULL;
}
void*retitem;
element=first;
*keyPtr=first->key;
if(err_type==1)
{
printf("Removeerror\n");
currentThread->Yield();
}
retitem=element->item;
if(first==last)
{
first=NULL;
last=NULL;
}
else
{
if(err_type==1)
{
printf("Removeerror\n");
currentThread->Yield();
}
first=element->next;
first->prev=NULL;
}
deleteelement;
returnretitem;
}
boolDLList:
:
IsEmpty()//returntrueiflisthaselements
{
if((first==NULL)&&(last==NULL))
returntrue;
elseif((first!
=NULL)&&(last!
=NULL))
returnfalse;
else
printf("error!
eitherthefirstorthelastisNULL!
\n");
returnfalse;
}
voidDLList:
:
SortedInsert(void*item,intsortKey)//routinestoput/getitemson/offlistinorder(sortedbykey)
{
DLLElement*insertItem=newDLLElement(item,sortKey);
DLLElement*ptr=first;
if(IsEmpty())
{
first=insertItem;
if(err_type==2)
{
printf("SortedInserterror,first!
=last\n");
currentThread->Yield();
}
last=insertItem;
}
else
{
for(;ptr!
=NULL;ptr=ptr->next)
if(ptr->key>sortKey)break;
if(err_type==3)
{
printf("SortedInserterror,thepostionlost\n");
currentThread->Yield();
}
if(ptr==NULL)
{
insertItem->prev=last;
last->next=insertItem;
last=insertItem;
last->next=NULL;
}
else
if(ptr==first)
{
insertItem->next=first;
first->prev=insertItem;
first=insertItem;
first->prev=NULL;
}
else
{
ptr->prev->next=insertItem;
insertItem->prev=ptr->prev;
if(err_type==4)
{
printf("SorteadInserterror,sorterror\n");
currentThread->Yield();
}
insertItem->next=ptr;
ptr->prev=insertItem;
}
}
}
void*DLList:
:
SortedRemove(intsortKey)//removefirstitemwithkey==sortKey
{//returnNULLifnosuchitemexists
DLLElement*ptr=first;
if(IsEmpty())
returnNULL;
for(;ptr!
=NULL;ptr=ptr->next)
if(ptr->key>sortKey)break;
if(ptr==NULL)
{
printf("Removeerror!
Nosuchakey!
");
returnNULL;
}
elseif(ptr==first)
{
first=first->next;
first->prev=NULL;
}
elseif(ptr==last)
{
last=last->prev;
last->next=NULL;
}
else
{
ptr->prev->next=ptr->next;
ptr->next->prev=ptr->prev;
}
returnptr->item;
}
Dllist-driver.cc
#include
#include"copyright.h"
#include"dllist.h"
#include"system.h"
#include
voidInsert(intt,intn,DLList*dllist)
{
inti,ll;
srand(time(0));
for(i=0;i{
ll=rand()%101;
dllist->SortedInsert(NULL,ll);
printf("Thread%d:
insertedkey=%d\n",t,ll);
}
}
voidRemove(intt,intn,DLList*dllist)
{
inti,keyll;
for(i=0;i{
dllist->Remove(&keyll);
printf("Thread%d:
removedkey=%d\n",t,keyll);
}
}
4、将上述要的链表文件拷贝nachos-3.4/code/threads/中,修改nachos-3.4/code/Mmon中的THREAD_H、THREAD_C、THREAD_O,在nachos-3.4/code/threads/目录中依次执行makedepend和make
修改nachos-3.4/code/threads/threadtest.cc和nachos-3.4/code/threads/main.cc实现两个线程调用链表功能,重新编译threads子系统
修改nachos-3.4/code/threads/threadtest.cc,在适当位置插入currentThread->Yield()调用以强制线程切换(注意相应文件中应该包含对外部变量currentThread的声明并includethread.h),重新编译threads子系统
Mmon
THREAD_H=../threads/copyright.h\
../threads/list.h\
../threads/dllist.h\
THREAD_C=../threads/main.cc\
../threads/dllist.cc\
../threads/dllist-driver.cc\
../threads/list.cc\
THREAD_O=main.odllist.odllist-driver.olist.o
Main.cc添加线程数,结点个数,错误类型,以及参数的修改
#ifdefTHREADS
externinttestnum;
externintthreadnum;
externintn;
externinterr_type;
#endif
#ifdefTHREADS
for(argc--,argv++;argc>0;argc-=argCount,argv+=argCount){
argCount=1;
switch(argv[0][1]){
case'q':
testnum=atoi(argv[1]);
argCount++;
break;
case't':
threadnum=atoi(argv[1]);
argCount++;
break;
case'n':
n=atoi(argv[1]);
argCount++;
break;
case'e':
err_type=atoi(argv[1]);
argCount++;
break;
default:
testnum=1;
break;
}
}
ThreadTest();
#endif
Threadtest.cc将双向链表的功能嵌入,设置测试号为2
//testnumissetinmain.cc
inttestnum=1,threadnum=1,n,err_type=0;
DLList*dllist;
void
DLListThread(intt)
{
Insert(t,n,dllist);
Remove(t,n,dllist);
}
void
ThreadTest2()
{
DEBUG('t',"EnteringThreadTest2");
dllist=newDLList(err_type);
for(inti=1;i{
Thread*t=newThread("forkerthread");
t->Fork(DLListThread,i);
}
DLListThread(threadnum);
}
//----------------------------------------------------------------------
//ThreadTest
//Invokeatestroutine.
//----------------------------------------------------------------------
void
ThreadTest()
{
switch(testnum){
case1:
ThreadTest1();
break;
case2:
ThreadTest2();
break;
default:
printf("Notestspecified.\n");
break;
}
5、相关并发错误分析
参照如下示例运行nachos
./nachos–q2–t2–n2–e0
-q2表示选择双向链表模式
-t为线程数
-n为插入结点数
-e为错误号
(1)无并发错误
./nachos–q2–t2–n2
(2)在remove中,由于线程切换,使返回值指向出错
./nachos–q2–t2–n4–e1
相关代码段:
void*retitem;
element=first;
*keyPtr=first->key;
if(err_type==1)
{
printf("Removeerror\n");
currentThread->Yield();
}
retitem=element->item;
(3)SortedInsert且链表为空时,由于进程切换,导致first与last指向有可能不一致。
./nachos–q2–t2–n4–e2
相关代码段:
if(IsEmpty())
{
first=insertItem;
if(err_type==2)
{
printf("SortedInserterror,first!
=last\n");
currentThread->Yield();
}
last=insertItem;
}
(4)SortedInsert时,将结点插入链表中时,由于进程切换,导致原来找到的结点位置丢失
./nachos–q2–t2–n4–e3
相关代码段:
for(;ptr!
=NULL;ptr=ptr->next)
if(ptr->key>sortKey)break;
if(err_type==3)
{
printf("SortedInserterror,thepostionlost\n");
currentThread->Yield();
}
(5)SortedInsert时,将结点插入链表中时,由于进程切换,导致结点间连接混乱
./nachos–q2–t2–n4–e4
相关代码段:
if(ptr==NULL)
{
insertItem->prev=last;
last->next=insertItem;
last=insertItem;
last->next=NULL;
}
else
if(ptr==first)
{
insertItem->next=first;
first->prev=insertItem;
first=insertItem;
first->prev=NULL;
}
else
{
ptr->prev->next=insertItem;
insertItem->prev=ptr->prev;
if(err_type==4)
{
printf("SorteadInserterror,sorterror\n");
currentThread->Yield();
}
insertItem->next=ptr;
ptr->prev=insertItem;
}
实验心得:
(1)在dllist-driver.cc中引用stdlib库时,若将库的引用的次序置于system.h与time.h之后,将可能引发声明的相关问题。
(2)在引用外部变量以及外部函数的时候必须要用extern声明。
(3)关于双向链表操作的代码其实并不难,关键是在对双向链表进行操作的时候,在适当的位置进行切换会引起不同的并发错误。
通过本次实验,熟悉了nachos中与本次实验相关的容,了解了线程的切换以及线程切换可能引发的并发错误。
实验分工:
实验代码编写三人先各自编写,最后讨论得出最终代码。