操作系统课程设计试验报告格式

四 川 大 学

操作系统课程设计报告

学    院:            软件                 

专    业:             软件工程              

年    级:               07                    

组 编 号:              X                   

组 成 员:     乔心轲(姓名) 0743111340(学号)

     何赵平(姓名) XXXXXXXX(学号)

     崔蓉  (姓名) XXXXXXXX(学号)

     张雯(姓名) XXXXXXXX(学号)

     康小芳(姓名) XXXXXXXX(学号)

提交时间:        2009             

指导教师评阅意见:                            

.                                             

.                                              .

  .                                              .

指导教师评阅成绩:XXX1:                    

XXX1:                    

XXX1:                    

XXX1:                    

XXX1:                    

实验项目一

项目名称:

实验目的:

实验时间:

人员分工:

实验环境:

实验环境的搭建过程、选用的操作系统、机器配置、编译器等。

实验内容:

对实践过程的详细说明,针对已经满足的实践要求,采用了何种算法或思想,对Nachos平台的哪些代码进行了什么样的修改。

实验结果:

对实践要求的满足程度,代码是否编写完成,是否调试通过,能否正常运行,本项目的要求中共满足了哪几项。

参考文献:


实验项目二

实验项目名称:Nachos中的线程管理

实验项目目的:

1.最多能够同时存在128个用户线程

2.改变为遵循“优先级调度”的抢占式调度

参与人员及分工:

乔心轲,何赵平,康小芳完成主要代码编写;

崔蓉,张文进行程序的测试及维护。

实验环境:

n  Nachos: Not Another Completely Heuristic Operating System

n  Linux

n  Gcc

n  Windows

实验内容:

1.对于最多能够同时存在128个用户线程,我们在Thread.cc中声明了一个static变量numOfThreads;具体代码如下:

static int numOfThreads = 0;//the count of the threads

在Thread的构造函数中对其值进行加1;即每创建一个线程时,都会把numOfThreads加1;

++numOfThreads;  

并在SimpleThread()中进行了如下修改,完成了最多能够同时存在128个用户线程。

static void

SimpleThread(int which)

{

   if(numOfThreads<128){     

      for(inti=0;i<(kernel->currentThread->Time())-(kernel->currentThread->executeTime)+2;i++){

        cout << "*** thread " <<which<<" looped "<<kernel->currentThread->executeTime<<" times.\n";

        cout<<"priority  "<<kernel->currentThread->Priority()<<"\n";       

        kernel->currentThread->Yield();

        }

   }

    else{

    if(count == 0)

        printf("The number of the threads can not be larger than 128!\n");

    kernel->currentThread->Yield();

       count++;

    }  

}

为了实现遵循“优先级调度”的抢占式调度策略,首先为Thread增加了三个变量:executeTime;time;priority

在Thread.h中对它们的声明:

public:

    Thread(char* debugName);        // initialize a Thread

    ~Thread();              // deallocate a Thread

                    // NOTE -- thread being deleted

                    // must not be running when delete

                    // is called

     int executeTime;//The time that this thread has executed

    

    // basic thread operation

    void setExTime(int exT);//set the executeTime of the thread to exT

    int Time();//return the time that the thread should be served

   

    void setTime(int t);//set the time that the thread should be served to t

     void setPriority(int pri);     //set the priority of the thread to pri

int Priority();             //return the priority of the thread  

private:

    // some of the private data for this class is listed above

    int time;                    // the time that the thread should be served     int priority;               //the priority of each thread

在Thread.cc中的实现:

Thread::Thread(char* threadName)

{

    name = threadName;

    stackTop = NULL;

    stack = NULL;

    status = JUST_CREATED;

   

    for (int i = 0; i < MachineStateSize; i++) {

       machineState[i] = NULL;      // not strictly necessary, since

                                    // new thread ignores contents

                        // of machine registers

     }

    space = NULL;

    executeTime=1;

    setPriority(0);

    setTime(2);

}

在Fork()中对numOfThreads进行了+1操作:

void

Thread::Fork(VoidFunctionPtr func, void *arg)

{    

    Interrupt *interrupt = kernel->interrupt;

    Scheduler *scheduler = kernel->scheduler;

    IntStatus oldLevel;

    DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);   

       StackAllocate(func, arg);

       oldLevel = interrupt->SetLevel(IntOff);

       scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts

                    // are disabled!

       (void) interrupt->SetLevel(oldLevel);      

      ++numOfThreads;      

}   

//---------------------------------------------------------------------

//Thread::setExTime

//     set the executeTime of the thread to exT

//---------------------------------------------------------------------

void

Thread::setExTime(int exT){

   executeTime = exT;

}

//---------------------------------------------------------------------

//Thread::setPriority

//     set the priority of the thread to pri

//---------------------------------------------------------------------

void

Thread::setPriority(int pri)

{

    priority=pri;

}

//---------------------------------------------------------------------

//Thread::Priority

//     return the priority of the thread

//---------------------------------------------------------------------

int

Thread::Priority(){

    return priority;

}

//---------------------------------------------------------------------

//Thread::setPriority

//     set the time of the thread to t

//---------------------------------------------------------------------

void

Thread::setTime(int t){

    time=t;

}

//---------------------------------------------------------------------

//Thread::Time

//     return the time of the thread need to run

//---------------------------------------------------------------------

int

Thread::Time(){

    return time;

}

并在SimpleThread()中进行了如下修改:

static void

SimpleThread(int which)

{

   if(numOfThreads<128){     

      for(int i=0;i<(kernel->currentThread->Time())-(kernel->currentThread->executeTime)+2;i++){

        cout << "*** thread " <<which<<" looped "<<kernel->currentThread->executeTime<<" times.\n";

        cout<<"priority   "<<kernel->currentThread->Priority()<<"\n";

       

        kernel->currentThread->Yield();

   

        }

   }

    else{

    if(count == 0)

        printf("The number of the threads can not be larger than 128!\n");

    kernel->currentThread->Yield();

       count++;

    }

   

}

对Scheduler.cc中进行了以下修改,实现了按照优先级进行线程的调度,返回最高优先级的线程,让其运行。

Thread *

Scheduler::FindNextToRun ()

{

    ASSERT(kernel->interrupt->getLevel() == IntOff);

    if (readyList->IsEmpty()) {

    return NULL;

    } else 

      {

           Thread *highestPri  = readyList->RemoveFront();

           for (int i =1;i<readyList->NumInList();i++){

          if(readyList->IsEmpty()){ 

            return highestPri;

          }      

          if(readyList->Front()->Priority()<=highestPri->Priority()){

            readyList->Append(highestPri);

            highestPri = readyList->RemoveFront();;

          }        

         }                 

        return highestPri;

    }

}

并在Run()中进行了以下修改:在Run()代码的最后加了以下语句:

kernel->currentThread->setPriority(kernel->currentThread->Priority()+1);

kernel->currentThread->setExTime(kernel->currentThread->executeTime+1);

实验结果和结论:

对实验进行的测试,首先编译通过测试:

经过编译测试,程序已完成了以上要求,具体测试如下:

对遵循“优先级调度”抢占式调度的实现:

void

Thread::SelfTest()

{

    DEBUG(dbgThread, "Entering Thread::SelfTest");

   for(int i=0;i<=3;i++){

    Thread *t = new Thread("forked thread");

    t->setPriority(3-i);

    t->Fork((VoidFunctionPtr) SimpleThread, (void *) numOfThreads);

}  

}

对最多只有128个用户线程存在的实现:

参考文献:


实验项目三

实验项目名称:Nachos中的文件管理系统

实验项目目的:

?   实现多个线程同时存在内存,虚拟地址到物理地址的转换,限制程序大小,不实现缺页中断处理

?   不实用虚拟内存

?   维护二类页表

– 实页页表(空闲页表):操作系统维护

(Machine中创建)——nachos现在有多少页表是可以供用户使用

– 线程页表:各线程维护自己的页表

参与人员及分工:

乔心轲,何赵平,康小芳完成主要代码编写;

崔蓉,张文进行程序的测试及维护。

实验环境:

n  Nachos: Not Another Completely Heuristic Operating System

n  Linux

n  Gcc

n  Windows

实验内容:

首先是在Machine.h中对空闲页表及其相关函数进行了声明:

  TranslationEntry *freePageTable;   //空闲页表

    TranslationEntry NextFreePage();//下一个空闲的页

     int NumOfFreePage();   //剩余空闲页的数目

其次在Machine.cc中空闲页表进行初始化以及函数的实现:

Machine::Machine(bool debug)

{

    int i;

    for (i = 0; i < NumTotalRegs; i++)

        registers[i] = 0;

    mainMemory = new char[MemorySize];

    for (i = 0; i < MemorySize; i++)

        mainMemory[i] = 0;

     freePageTable = new TranslationEntry[NumPhysPages];

     for (i = 0; i < NumPhysPages; i++) {

    freePageTable[i].virtualPage=i;

    freePageTable[i].physicalPage = i;

    freePageTable[i].valid = TRUE;

    freePageTable[i].use = FALSE;

    freePageTable[i].dirty = FALSE;

    freePageTable[i].readOnly = FALSE; 

    }   

#ifdef USE_TLB

    tlb = new TranslationEntry[TLBSize];

    for (i = 0; i < TLBSize; i++)

    tlb[i].valid = FALSE;

    pageTable = NULL;

#else   // use linear page table

    tlb = NULL;

    pageTable = NULL;

#endif

    singleStep = debug;

    CheckEndian();

}  

//----------------------------------------------------------------------

//Machine::NextFreePage()

//----------------------------------------------------------------------

TranslationEntry

Machine::NextFreePage(){

     for(int i = 0;i<NumPhysPages;i++)

        {

            if(freePageTable[i].valid==TRUE)

        return freePageTable[i];

        }

}

//----------------------------------------------------------------------

//Machine::numOfFreePage()

//----------------------------------------------------------------------

int

Machine::NumOfFreePage(){

    int num = 0;

     for(int i = 0;i<NumPhysPages;i++)

        {

            if(freePageTable[i].valid==TRUE)

        num++;

        }

     return num;

}

对AddrSpace.cc的修改如下:

AddrSpace::AddrSpace()

{  

 

}

AddrSpace::~AddrSpace()

{

   if(pageTable!=NULL){

     for(int i=0;i<numPages;i++){

        pageTable[i].valid = TRUE;

        pageTable[i].use = FALSE;

        pageTable[i].dirty = FALSE;

        pageTable[i].readOnly = FALSE; 

    }

    delete pageTable;

   } 

  

}

为了实现限制程序大小以及实现线程页表和空闲页表的转换,对代码进行了如下修改:

bool

AddrSpace::Load(char *fileName)

{

    OpenFile *executable = kernel->fileSystem->Open(fileName);

    NoffHeader noffH;

    unsigned int size;

    if (executable == NULL) {

    cerr << "Unable to open file " << fileName << "\n";

    return FALSE;

    }

    executable->ReadAt((char *)&noffH, sizeof(noffH), 0);

    if ((noffH.noffMagic != NOFFMAGIC) &&

        (WordToHost(noffH.noffMagic) == NOFFMAGIC))

        SwapHeader(&noffH);

    ASSERT(noffH.noffMagic == NOFFMAGIC);

#ifdef RDATA

// how big is address space?

    size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +

           noffH.uninitData.size + UserStackSize;  

                                                // we need to increase the size

                        // to leave room for the stack

#else

// how big is address space?

    size = noffH.code.size + noffH.initData.size + noffH.uninitData.size

            + UserStackSize;    // we need to increase the size

                        // to leave room for the stack

#endif

    numPages = divRoundUp(size, PageSize);

    size = numPages * PageSize;

    ASSERT(numPages <= NumPhysPages);       // check we're not trying

                        // to run anything too big --

                        // at least until we have

                        // virtual memory

   

    DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);

    pageTable = new TranslationEntry[numPages];

    if(kernel->machine->NumOfFreePage()>=numPages){

        for(int i=0;i<numPages;i++){

            TranslationEntry temp = kernel->machine->NextFreePage();

            pageTable[i].virtualPage=temp.virtualPage;

            pageTable[i].physicalPage=temp.physicalPage;

            pageTable[i].valid=FALSE;

            pageTable[i].use=FALSE;        

            kernel->machine->freePageTable[temp.physicalPage].valid = FALSE;

            kernel->machine->freePageTable[temp.physicalPage].use = TRUE;          

            } 

//sgeTable[i].virtualPage=0;

// then, copy in the code and data segments into memory

// Note: this code assumes that virtual address = physical address

  int i=0;

if (noffH.code.size > 0) {

        DEBUG(dbgAddr, "Initializing code segment.");

     DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);

     for(;i<(noffH.code.size/PageSize);i++){

        executable->ReadAt(

            &(kernel->machine->mainMemory[pageTable[i].physicalPage]),

             PageSize,  noffH.code.inFileAddr+i*PageSize);

        cout<<"Page "<<pageTable[i].virtualPage<<" for code segment is used!\n";

        }

    }

   cout<<"Page for code is allocated\n";

   if (noffH.initData.size > 0) {

    DEBUG(dbgAddr, "Initializing data segment.");

    DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);

    for(;i<(noffH.code.size/PageSize)+(noffH.initData.size/PageSize);i++){     

        executable->ReadAt(

            &(kernel->machine->mainMemory[pageTable[i].physicalPage]),

             PageSize, noffH.initData.inFileAddr+i*PageSize);

        cout<<"Page "<<pageTable[i].virtualPage<<" for data segment is used!\n";

        }

        }

#ifdef RDATA

    if (noffH.readonlyData.size > 0) {

    DEBUG(dbgAddr, "Initializing read only data segment.");

    DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);

for(;i<(noffH.code.size/PageSize)+(noffH.initData.size/PageSize)+(noffH.readonlyData.size/PageSize);i++){

              executable->ReadAt(

                &(kernel->machine->mainMemory[pageTable[i].physicalPage]),

                 PageSize,  noffH.readonlyData.inFileAddr+i*PageSize);

        cout<<"Page "<<pageTable[i].virtualPage<<" for readOnlydata segment is used!\n";

        }

    }

#endif

     }

   

else{

cout<<"Not enough space for the program!\n";

delete pageTable;

}  

       

    delete executable;          // close file

    return TRUE;            // success

}

实验结果和结论:

程序已编译通过,实现了

1.多个线程同时存在内存,虚拟地址到物理地址的转换,限制程序大小,不实现缺页中断处理

2.维护二类页表

(1)实页页表(空闲页表):操作系统维护(Machine中创建)——nachos现在有多少页表是可以供用户使用

(2)线程页表:各线程维护自己的页表

具体如下:

编译通过:

测试:

参考文献:


实验项目四

实验项目名称:Nachos中的文件管理模块升级

实验项目目的:

l  多个线程不能同时对一个文件进行写操作,因为会发生冲突,但是可以同时进行读操作.

l  将简单的通过信号量进行控制的同步机制修改为读者/写者问题的机制.

l  实现目录结构的多级机制

参与人员及分工:

实验环境:

n  Nachos: Not Another Completely Heuristic Operating System

n  Linux

n  Gcc

n  Windows

实验内容:

实现多个线程不能同时对一个文件进行写操作,因为会发生冲突,但是可以同时进行读操作. 将简单的通过信号量进行控制的同步机制修改为读者/写者问题的机制:

在SynchDisk.h中的修改如下:

  private:

    int readcount;                       //count the number of the readers

    int writecount;                    //count the number of the writers

   

    Disk *disk;             // Raw disk device

    Semaphore *x;  

    Semaphore *y;

    Semaphore *z;

    Semaphore *wsem;

Semaphore *rsem;

在SynchDisk.cc中的构造函数中对信号量进行初始化。

SynchDisk::SynchDisk()

{

    x = new Semaphore("synch disk", 1);

    y= new Semaphore("synch disk", 1);

    z = new Semaphore("synch disk", 1);

    wsem= new Semaphore("synch disk", 1);

    rsem= new Semaphore("synch disk", 1);

    lock = new Lock("synch disk lock");

    disk = new Disk(this);

    readcount=0;

    writecount=0;

}

在SynchDisk.cc中的析构函数中把信号量的指针删除。

SynchDisk::~SynchDisk()

{

    delete disk;

    delete lock;

    delete x;

    delete y;

    delete z;

    delete wsem;

    delete rsem;

}

在ReadSector函数中进行的修改如下:

void

SynchDisk::ReadSector(int sectorNumber, char* data)

{

while(TRUE)

{

    z->P();//只有一个读进程可以进入

    rsem->P();

    x->P();

    readcount++;

    if(readcount==1)

    wsem->P();

     x->V();

     rsem->V();

     z->V();

     x->P();

         lock->Acquire();          

         disk->ReadRequest(sectorNumber, data);   

         lock->Release();

     x->V();

     readcount--;

     if(readcount==0)

    wsem->V();

     x->V();

}

}

void

SynchDisk::WriteSector(int sectorNumber, char* data)

{

while(TRUE){

y->P();

//多个写进程可以进行排队

writecount++;

if(writecount==1)

    rsem->P();

y->V();

wsem->P();

lock->Acquire();           

disk->WriteRequest(sectorNumber, data);

lock->Release();

wsem->V();

y->P();

writecount--;

if(writecount==0)

    rsem->V();

y->V();

}

}

实现目录结构的多级机制:

创建了一个SubFileHeader类:

主要就是把FileHeader的内容拷贝过去了;

然后在FileHeader中进行了如下修改:

bool

FileHeader::Allocate(PersistentBitmap *freeMap, int fileSize)

{

int hdr_size;

SubFileHeader *subHdr[30];

numBytes = fileSize;

if(fileSize<NumDirect*SectorSize)

{

    printf("filehdr.cc 50 -->\n");

    numHdrSectors  = divRoundUp(fileSize, SectorSize);

    if (freeMap->NumClear() < numHdrSectors)

return FALSE;       // not enough space

    for (int i = 0; i < numHdrSectors; i++)

dataSectors[i] = freeMap->FindAndSet();

    return TRUE;

}

else{

       numHdrSectors= divRoundUp(fileSize, SectorSize*30);

    if (freeMap->NumClear() < numHdrSectors*NumDirect)

return FALSE;       // not enough space

for (int i = 0; i < NumDirect; i++){

dataSectors[i] = -1;

}

for(int i=0;i<numHdrSectors;i++)

{

subHdr[i]= new SubFileHeader;

dataSectors[i]=freeMap->FindAndSet();

printf("Another file header in sector %d \n",dataSectors[i]);

if(i<numHdrSectors-1)

subHdr[i]->Allocate(freeMap, 30*SectorSize);

else if(i==numHdrSectors-1)

   subHdr[i]->Allocate(freeMap, fileSize-30*SectorSize*i);

   subHdr[i]->WriteBack(dataSectors[i]);

printf("filehdr  63\n");

}

}

delete subHdr;

return true;

}

//----------------------------------------------------------------------

// FileHeader::Deallocate

// De-allocate all the space allocated for data blocks for this file.

//

//  "freeMap" is the bit map of free disk sectors

//----------------------------------------------------------------------

void

FileHeader::Deallocate(PersistentBitmap *freeMap)

{

if(numBytes<NumDirect*SectorSize)

{

 for (int i = 0; i < numHdrSectors; i++) {

ASSERT(freeMap->Test((int) dataSectors[i]));  // ought to be marked!

freeMap->Clear((int) dataSectors[i]);}

}

else{

    for (int i = 0; i < numHdrSectors; i++) {

  SubFileHeader *hdr= new SubFileHeader;

    hdr->FetchFrom(dataSectors[i]);

    hdr->Deallocate(freeMap);

    }   

}

}

实验结果和结论:

程序已编译通过,并实现了

1.多个线程不能同时对一个文件进行写操作,因为会发生冲突,但是可以同时进行读操作.

2.将简单的通过信号量进行控制的同步机制修改为读者/写者问题的机制.

3.实现目录结构的多级机制

首先,编译通过:

参考文献:

相关推荐