当前位置:文档之家› 操作系统nachos课程设计实验报告

操作系统nachos课程设计实验报告

操作系统nachos课程设计实验报告
操作系统nachos课程设计实验报告

一题目

project1:实现nachos操作系统的project1中的join()方法,condition2 类,Alarm类,Communicator类,PriorityScheduler类和Boat类

project2:实现nachos操作系统的project2中的creat open read write close unlink 文件系统调用,修改UserProcess.readVirtualMemory和UserProcess.writeVirtualMemory使操作系统能够运行多用户程序,实现exec join exit系统调用,实现LotteryScheduler类

二实验目的

熟悉nachos操作系统,深入理解操作系统内核

了解用户程序的加载过程以及多用户进程的内存分配机制

三实验要求

完成nachos,提交设计文档和你的代码

四实验说明,程序代码及测试结果

Project1:

1 join()

要求实现join()方法,注意,其他线程没必要调用join函数,但是如果它被调用的话,也只能被调用一次。join()方法第二次调用的结果是不被定义的,即使第二次调用的线程和第一次调用的线程是不同的。无论有没有被join,一个进程都能够正常结束

(a)设计思想

当线程B执行A.join()时,将B放入A的等待队列,直到A完成时,唤醒在等待队列中的所有线程,因此需要实现join()方法和修改finish方法(b)源代码

public void join(){

Lib.debug(dbgThread, "Joining to thread:" + toString());

Lib.assertTrue(this!=currentThread);

Lib.assertTrue(join_counter == 0);

join_counter++;

boolean status=Machine.interrupt().disable();

if (this.status != statusFinished) {

waitQueue.waitForAccess(KThread.currentThread());

currentThread.sleep();

}

Machine.interrupt().restore(s tatus);

}

public static void finish(){

Lib.debug(dbgThread, "Finishing thread:" +

currentThread.toString());

Machine.interrupt().disable();

Machine.autoGrader().finishingCurrentThread();

Lib.assertTrue(toBeDestroyed == null);

toBeDestroyed= currentThread;

currentThread.status = statusFinished;

KThread thread= currentThread().waitQueue.nextThread();

if (thread!= null)

{

thread.ready();

}

sleep();

}

(c)程序截图

线程1每次执行打出执行的次数,每次执行过后放弃cpu,线程2 打出successful,线程2 执行thread1.join().通过截图可以看出代码正确

2 Condition2

通过使用开关中断提供原子性来直接实现条件变量,我们利用信号量提供了一个简单的实现方式,你的工作就是不直接使用信号量提供相同的实现(你或许使用锁,即使它们也间接的使用了信号量)。一旦你实现了,你将会有两

种可选择的实现方式来提供相同的功能。你的第二种条件变量的实现必须放在Condition2 中

(a)设计思想

Condition2 是对使用该条件变量的线程进行管理,所以要把在这个条件变量上等待的进程储存起来,因此可以使用一个队列。

sleep()方法是把等待该条件变量的线程阻塞,放入等待队列,直到执行了wake()并且获得cpu 才能继续执行,执行步骤:关中断,释放锁,把线程放入等待队列,获得锁,开中断。

wake()方法是把条件变量中的线程移出,放入就绪队列。执行步骤:关中断,线程移出等待队列移入就绪队列,开中断

wakeAll()方法是将条件变量中的所有线程移出,移入就绪队列

(b)源代码

public void sleep(){

Lib.assertTrue(conditionLock.isHeldByCurrentThread());

boolean status=Machine.interrupt().disable();

conditionLock.release();

waitqueue.waitForAccess(KThread.currentThread());

KThread. currentThread().sleep();

conditionLock.acquire();

Machine.interrupt().restore(s tatus);

}

public void wake(){

Lib.assertTrue(conditionLock.isHeldByCurrentThread());

boolean status=Machine.interrupt().disable();

KThread thread=waitqueue.nextThread();

if (!(thread==null))

thread.ready();

Machine.interrupt().restore(s tatus);

}

public void wakeAll(){

Lib.assertTrue(conditionLock.isHeldByCurrentThread());

boolean status=Machine.interrupt().disable();

KThread thread=waitqueue.nextThread();

while(!(thread==null))

{ thread.ready();

thread=waitqueue.nextThread();

}

Machine.interrupt().restore(s tatus);

}

(c)程序截图

线程1线程 2 分别请求锁和条件变量,然后释放锁和条件变量,图中可以看出代码正确

3 Alarm类

实现Alarm 类,线程调用waitUntil方法之后会终止,直到传入的时间之后

才可以执行。线程没必要在等待的时间之后立刻执行,只是把它放入ready队列,等待分配cpu。可以使用一个线程队列,但是不能产生额外的线程。(a)设计思想

waitUntil()方法使用了一个队列可以存放线程以及唤醒时间,这个队列以时间为序的有序队列。每次调用时,把当前线程和唤醒时间加入队列,等待唤醒。

timerInterrupt()方法在每一次timer 产生时间中断时遍历队列,检查队列中的时间状态,当线程到了等待的时间就把线程从队列中取出放入就绪队列。

KThreadWakeTime类是一个内部类用于联系线程和唤醒时间

(b)源代码

public void waitUntil(long x) {

boolean status=Machine.interrupt().disable();

long waketime= Machine.timer().getTime() + x;

KThreadWakeTime kthreadwaketime=new

KThreadWakeTime(KThread.currentThread(),

waketime);

int size=linkedlist.size();

if (size== 0)

linkedlist.add(kthreadwaketime);

else

for (int i = 0; i

if (waketime< linkedlist.get(i).getWakeTime())

{ linkedlist.add(i, kthreadwaketime);

break;

}

if (i==size-1

&& waketime>= linkedlist.get(i).getWakeTime())

linkedlist.add(i + 1, kthreadwaketime);

}

KThread. currentThread().sleep();

Machine.interrupt().restore(s tatus);

}

public void timerInterrupt(){

boolean status=Machine.interrupt().disable();

long currenttime= Machine.timer().getTime();

int size=linkedlist.size();

if (size== 0)

;

else

for (int i = 0; i

if (currenttime< linkedlist.get(i).getWakeTime());

else {

KThread thread= linkedlist.get(i).getThread();

thread.ready();

linkedlist.remove(i);

size--;

i = 0;

currenttime= Machine.timer().getTime();

}

}

KThread.currentThread ().yield();

Machine.interrupt().restore(s tatus);

}

public class KThreadWakeTime{

private KThread thread= null;

private long waketime=0;

public KThreadWakeTime(KThread thread,long waketime)

{this.thread = thread;

this.waketime =waketime;

}

public KThread getThread(){

return thread;

}

public long getWakeTime(){

return waketime;

}

}

(c)程序截图

创建一个线程在70时中止,等待500后唤醒。图中可以看出代码正确

4 Communicator

利用条件变量编写发送和接收一个消息来实现Communicator类的speak ()和listen()方法。speak()要自动等待listen()被调用,然后将消息传

递给listen()。同样的listen()也要自动等待speak()被调用,将消息传递

给自己才能收到一个消息。只有消息从speak()传递到了listen()两个线程

才能返回。在只有一个Communicator对象时也能工作起来,不能拥有缓冲区,也就是说listen()和speak()只有成功配对之后才能传递消息。(a)设计

思想

speak():先获得锁,然后进行判断,如果没有听者等待,就要把说者放

入队列然后睡眠。如果有听者等待,就要唤醒一个听者,然后传递消息,最后

释放锁。

listen():先获得锁,然后进行判断,如果没有说者等待,就要把听者放

入队列然后睡眠。如果有说者等待,就要唤醒一个说者,然后传递消息,最后

释放锁。

(b)

public Communicator(){

lock=new Lock();

queue=new LinkedList();

speaker=new Condition2(lock);

listener=new Condition2(lock);

word=0;

speakercount=0;

listenercount=0;

}

public void speak(int word) {

boolean intStatus= Machine.interrupt().disable();

lock.acquire();

if(listenercount==0)

{

speakercount++;

queue.offer(word);

speaker.sleep();

listener.wake();

speakercount--;

}

else

{queue.offer(word);

listener.wake();

}

lock.release();

Machine.interrupt().restore(i ntStatus);

return;

}

public int listen(){

boolean intStatus= Machine.interrupt().disable();

lock.acquire();

if(speakercount!=0)

{speaker.wake();

listener.sleep();

}

else

{listenercount++;

listener.sleep();

listenercount--;

}

lock.release();

Machine.interrupt().restore(i ntStatus);

return queue.poll();

}

(c)程序截图

线程1和线程2分别调用speak()将20,30 传递,线程3和线程4 调用listen ()将消息接收。线程1 和线程2执行时没有听者,双双等待,证明程序在多个说者和听者时也能工作的很好

5 PriorityScheduler类

通过完成实现PriorityScheduler优先级调度策略。所有的调度程序都是继承自Scheduler 类,所以必须实现g etPriority(), getEffectivePriority()和setPriority()方法。在调度中必须选择有效优先级最长的执行,如果有效优先级相同的线程都在等待要选择等待时间最长的。解决优先级问题的关键就是优先级反转,当一个高优先级的线程等待一个低优先级的线程时,高优先级的线程就必须把自己的有效优先级捐献给低优先级的线程,让低优先级的线程提高优先级可以尽快执行。解决这个问题的关键就是计算有效优先级,但是计算时间不能太长,所以在改变优先级的时候在计算比较合适。优先级在捐献之后不会丢失。优先级可以不断传递下去。

(a)设计思想

在引入优先级的同时就需要引入一个ThreadState对象,它用来把线程和

优先级绑定在一起。而且内部还有一个队列用来记录等待它的线程。在执行getEffectivePriority()方法时,要遍历整个队列,将等待它线程的最高有效优先级取出,和自己的优先级比较,把最大的当成自己的最高有效优先级。而在遍历的过程中,如果线程还有等待的线程还要计算自己的有效优先级,所以这是一个递归搜索的过程。而在队列类中最重要的就是nextThread()方法,它返回下一个要执行的线程。这个方法通过遍历队列,计算出所有线程的有效优先级,取出有效优先级最大的线程执行。

(b)源代码

public int getEffectivePriority(){

effectivepriority=-1;

for(int i=0;i

{if(waitQueue.waitQueue.get(i).getEffectivePriority()>effectivepr iority)

effectivepriority=waitQueue.waitQueue.get(i).getEffectivePriority();

}

if(effectivepriority>priority)

setPriority(effectivepriority);

return priority;

}

public KThread nextThread(){

Lib.assertTrue(Machine.interrupt().disabled());

int max=-1;

index=0;

ThreadState state=null,temp=null;

while((temp=pickNextThread())!=null)

{if(temp.getEffectivePriority()>max)

{state=temp;

max=temp.getEffectivePriority();}

}

if(state==null)

{return null; }

else

{return waitQueue.remove(w aitQueue.indexOf(s tate)).thread;}}

protected ThreadState pickNextThread(){

if(index

{index++;

return waitQueue.get(index-1);}

return null;

}

(c)程序截图

创建三个线程thread1,thread2,thread3,分别赋予优先级为2,4,6,thread3 中调用了thread1.join()。运行之后,thread1得到了thread3的优先级,有效优先级最高,最先执行,当thread1执行完成之后,thread3的优先级最高,第二执行,thread2优先级最低最后执行。

6 Boat

使用条件变量解决过河问题。O岛有一群人要到M岛去,但是只有一艘船,这艘船一次只能带一个大人或者两个孩子。开始必须假设至少有两个孩子(否则问题无法解决),每一个人都会划船。要为每个大人和孩子创建一个线程,这个线程就相当于一个人,他们能自己判断(思考),什么时候可以过河,而不是通过调度程序的调度。在解决问题的过程中不能出现忙等待,而且问题最终一定要解决。不符合逻辑的事情不能发生,比如在这个岛的人能知道对面岛的情况。

(a)设计思想

创建两种类型的线程大人线程和孩子线程,他们分别执行不同的行为。船设置成为条件变量,人的位置,该大人还是孩子走,船是否在一个岛上设置成为布尔变量,将问题建模为数学问题。

大人进程:首先要获得锁,然后进行判断是否是大人要走,船是否在这个岛上,如果不成立大人就要等待直到成立然后大人过河,改变变量的值,到达对岸之后唤醒一个孩子把穿开回来

孩子进程:首先要获得锁,首先判断是在哪个岛上;若在O岛,则判断运输过程是否已经结束,要是结束就不执行任何操作,要是没结束,判断是否是孩子走,船是否在这个岛上,如果不成立,孩子就要等待直到成立,两个孩子过河,改变变量的值,并且还要把是否结束的信息传递过来。如果结束不做任何操作,否则唤醒一个孩子进程把船开回去;若在M岛,则孩子直接过河,并且根据获得信息要求下一次是大人还是孩子过河。

(b)源代码

public static void begin(int adults, int children, BoatGrader b) { bg = b;

parentThread= KThread.currentThread();

for (int i = 0; i

new KThread(new Runnable() {

public void run(){

AdultItinerary();

}

}).fork();

for (int i = 0; i

new KThread(new Runnable() {

public void run(){

ChildItinerary();

}

}).fork();

children_number_Oahu= children;

adult_number_Oahu= adults;

children_number_Molokai= 0;

adult_number_Molokai= 0;

lock =new Lock();

children_condition_Oahu= new Condition(lock);

children_condition_Molokai= new Condition(lock);

adult_condition_Oahu= new Condition(lock);

is_pilot=true;

is_adult_go= false;

is_end=false;

boat_in_Oahu= true;

}

static void AdultItinerary()

{ bg.initializeAdult();

lock.acquire();

if (!(is_adult_go&& boat_in_Oahu))

{ adult_condition_Oahu.sleep();

}

bg.AdultRowToMolokai();

adult_number_Oahu--;

adult_number_Molokai++;

is_adult_go= false;

boat_in_Oahu= false;

children_condition_Molokai.wake();

lock.release();

}

static void ChildItinerary()

{ bg.initializeChild();

boolean is_on_Oahu= true;

boolean is_first_go=true;

lock.acquire();

while(!is_end) {

if (is_on_Oahu) {

if (!boat_in_Oahu|| is_adult_go)

{

children_condition_Oahu.sleep();

}

if(is_pilot)

{bg.ChildRowToMolokai();

is_on_Oahu=false;

children_number_Oahu--;

children_number_Molokai++;

is_pilot=false;

children_condition_Oahu.wake();

children_condition_Molokai.sleep();

}

else

{

if (adult_number_Oahu== 0&& children_number_Oahu== 1)

is_end=true;

if(adult_number_Oahu!= 0)

is_adult_go=true;

bg.ChildRideToMolokai();

is_on_Oahu=false;

boat_in_Oahu= false;

children_number_Oahu--;

children_number_Molokai++;

is_pilot=true;

if(!is_end)

{

children_condition_Molokai.wake();

}

children_condition_Molokai.sleep();

}

}

else {

bg.ChildRowToOahu();

is_on_Oahu=true;

boat_in_Oahu= true;

children_number_Molokai--;

children_number_Oahu++;

if (adult_number_Oahu== 0){

is_adult_go= false;

children_condition_Oahu.wake();

} else {

if(is_adult_go)

adult_condition_Oahu.wake();

else

children_condition_Oahu.wake();

}

children_condition_Oahu.sleep();

}

}

}

(c)程序截图

这是三个孩子和三个大人的情况,图中显示程序正确。

Project2:

1 creat open read write close unlink文件系统调用

必须保证操作系统的内核不受到用户的错误影响,换句话说,用户进程产生的错误参数不能传入内核。修改halt()方法只能根进程可以调用;必须使用UserProcess.readVirtualMemory和UserProcess.writeVirtualMemory来把地址和参数传入。作为参数传递的字符串最长为256.文件描述符0和1是标准的输入输出流,不用open方法就能打开不用实现任何形式的锁,需要的只是提供的文件系统完成系统调用

(a)设计思想

halt():设置一个进程号,只有进程号为0的进程(也就是第一个进程)才能调用

creat():先从内存中将文件名读出,然后利用文件系统的打开文件。利用不存在就创建的方法,在物理磁盘中创建文件。

open():先从内存中将文件名读出,然后利用文件系统的打开文件。利用不存在直接返回null,仅打开

read():使用打开文件描述符,利用文件系统的读方法将数据从文件中读

到数组中,然后使用内存写操作,写入内存。返回写入的数量write():使用打开文件描述符,利用内存读操作将数据从内存中读到数组中,然后使用文件写操作,写入文件。返回写入的数量close():使用打开文件描述符,将文件描述符指向的文件利用文件系统的关闭方法关闭

unlink():先从内存中将文件名读出,利用文件系统的删除操作将文件从物理磁盘中删除

(b)源代码

private int handleHalt(){

if(pid==0)

Machine.halt();

Lib.assertNotReached("Machine.halt() did not halt machine!");

return0;

}

private int handleCreate(int fileAddress) {

String filename=readVirtualMemoryString(fileAddress,256);

if(filename==null)

return-1;

int fileDescriptor=findEmpty();

if(fileDescriptor==-1)

return-1;

else

{openfile[fileDescriptor]=ThreadedKernel.fileSystem.open(filename, true);

return fileDescriptor;

}

}

private int handleOpen(int fileAddress) {

String filename=readVirtualMemoryString(fileAddress,256);

if(filename==null)

return-1;

int fileDescriptor=findEmpty();

if(fileDescriptor==-1)

return-1;

else

{openfile[fileDescriptor]=ThreadedKernel.fileSystem.open(filename, false);

return fileDescriptor;

}

}

private int handleRead(int fileDescriptor,int bufferAddress,int

length) {

if(fileDescriptor>15||fileDescriptor<0||openfile[fileDescriptor]= =null)

return-1;

byte temp[]=new byte[length];

int readNumber=openfile[fileDescriptor].read(temp, 0, length);

if(readNumber<=0)

return0;

int writeNumber=writeVirtualMemory(bufferAddress,temp);

return writeNumber;

}

private int handleWrite(int fileDescriptor,int bufferAddress,int length){

if(fileDescriptor>15||fileDescriptor<0||openfile[fileDescriptor]= =null)

return-1//文件未打开,出错

byte temp[]=new byte[length];

int readNumber=readVirtualMemory(bufferAddress,temp);

if(readNumber<=0)

return0;//没读出数据

int writeNumber=openfile[fileDescriptor].write(temp, 0,length);

if(writeNumber

return-1;//未完全写入,出错

return writeNumber;

}

private int handleClose(int fileDescriptor) {

if(fileDescriptor>15||fileDescriptor<0||openfile[fileDescripto

r]==null)

return-1;//文件不存在,关闭出错

openfile[fileDescriptor].close();

openfile[fileDescriptor]=null;

return0;

}

private int handleUnlink(int fileAddress) {

String filename=readVirtualMemoryString(fileAddress,256);

if(filename==null)

return0;

if(ThreadedKernel.fileSystem.remove(filename))

return0;

else

return-1;

}

private int findEmpty()

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

{if(openfile[i]==null)

return i;

}

return-1;

}

2 readVirtualMemory()writeVirtualMemory()

实现多进程并发执行。提出一种内存分配方法使每个用户进程能够使用属于自己的内存。没必要是动态内存分配,每个程序在执行之前就知道自己需要多少进程。建议使用一个全局的内存页链表,而且在分配内存时应该有同步。应该才有内存池,使用一页一页的内存而不是一大块。进程退出时应该释放所有的内存。应该使用页表来将物理地址与逻辑地址对应起来,而且页表中应该指出文件是否为只读。

(a)设计思想

在loadSection中,在导入coff之前应该创建一个页表,进行物理地址和逻辑地址的关联,然后把程序的每一块按照顺序对应于物理地址导入到内存中。读内存时,要先利用页表将逻辑地址转换为物理地址然后再将内存数据复制到数组中

写内存时,要先利用页表将逻辑地址转换为物理地址然后再将内存数据复制到数组中

(b)源代码

protected boolean loadSections(){

UserKernel.allocateMemoryLock.acquire();

if (numPages> UserKernel.memoryLinkedList.size())

{ coff.close();

Lib.debug(dbgProcess, "\tinsufficient physical memory");

UserKernel.allocateMemoryLock.release();

return false;

}

pageTable= new TranslationEntry[numPages];//创建页表

for (int i = 0; i

{ int nextPage=UserKernel.m emoryLinkedList.remove();

pageTable[i] = new TranslationEntry(i, nextPage, true, false, false, false);

}

UserKernel.allocateMemoryLock.release();

for (int s = 0; s

{ CoffSection section= coff.getSection(s);

Lib.debug(dbgProcess, "\tinitializing" +

section.getName()+" section(" + section.getLength()+ " pages)");

for (int i = 0; i

int vpn=section.getFirstVPN()+i;

pageTable[vpn].readOnly=section.isReadOnly();

section.loadPage(i, pageTable[vpn].ppn);

}

}

return true;

}

public int readVirtualMemory(int vaddr, byte[] data, int offset, int length) {

Lib.assertTrue(offset >= 0&& length>= 0

&& offset+ length<= data.length);

byte[] memory =Machine.processor().getMemory();

if(length>(pageSize*numPages-vaddr))

length=pageSize*numPages-vaddr;

if(data.length-offset

length=data.length-offset;

int transferredbyte=0;

do{int

pageNum=Processor.pageFromAddress(vaddr+transferredbyte);

if(pageNum<0||pageNum>=pageTable.length)

return0;

int

pageOffset=Processor.o ffsetFromAddress(vaddr+transferredbyte);

int leftByte=pageSize-pageOffset;

int amount=Math.min(leftByte, length-transferredbyte); int

realAddress=pageTable[pageNum].ppn*pageSize+pageOffset;

System.arraycopy(memory, realAddress,data,

offset+transferredbyte, amount);

transferredbyte=transferredbyte+amount;}

while(transferredbyte

return transferredbyte;

}

public int writeVirtualMemory(int vaddr, byte[] data, int offset,

int length) {

Lib.assertTrue(offset >= 0&& length>= 0

&& offset+ length<= data.length);

byte[] memory =Machine.processor().getMemory();

if(length>(pageSize*numPages-vaddr))

length=pageSize*numPages-vaddr; if(data.length-

offset

length=data.length-offset;

int transferredbyte=0;

do{

int pageNum=Processor.pageFromAddress(vaddr+transferredbyte);

if(pageNum<0||pageNum>=pageTable.length)

return0;

int

pageOffset=Processor.o ffsetFromAddress(vaddr+transferredbyte);

int leftByte=pageSize-pageOffset;

int amount=Math.min(leftByte, length-transferredbyte);

int realAddress=pageTable[pageNum].ppn*pageSize+pageOffset;

System.arraycopy(data, offset+transferredbyte, memory, realAddress, amount);

transferredbyte=transferredbyte+amount;

}

while(transferredbyte

return transferredbyte;

}

3 exec join exit系统调用

寄存器传递的所有的参数都是内存的地址,所以需要读写内存来获得真正参数。孩子进程的状态是私有的,所以不能使用共享内存的方式。进程号可以做为参数传递给join方法用来指明父进程将要join哪一个孩子进程。最后一个执行exit的方法将关闭系统,但是直接调用Machine.halt().

(a)设计思想

exec: 先从内存中将文件名读出,然后将参数表从内存中读出,创建一个新的用户进程,将文件和参数表加载到子进程,运行子进程,同时将这个子进程的父进程置为这个进程,再将子进程加入子进程列表。

join:利用进程号确定join的是哪一个进程,先遍历子进程链表,确定join的进程是子进程,获得join锁,让该进程休眠,直到子进程唤醒,子进程唤醒之后将子进程的状态存入自己的内存中

exit:首先关闭coff,然后将所有的打开文件关闭,把退出的状态置入,如果

该进程有父进程,看是否执行了join方法,如果执行就将其唤醒,同时将本进程从子进程链表中删除,释放内存,结束底层线程,如果是最后一个结束的进程则将系统关闭

(b)源代码

private int handleExec(int fileAddress, int argc, int argvAddress) { String filename=readVirtualMemoryString(fileAddress,256);

if(filename==null||argc<0||argvAddress<0||argvAddress>numPages*pa geSize)

return-1;

String[]args=new String[argc];

for(int i=0;i

{byte[] argsAddress=new byte[4];

if(readVirtualMemory(argvAddress+i*4,argsAddress)>0)

args[i] = readVirtualMemoryString(Lib.bytesToInt(argsAddress, 0),256);

}

UserProcess process=UserProcess.n ewUserProcess();

if(!process.execute(filename,args))

return-1;

process.parentProcess=this;

childProcess.add(process);

return process.pid;

}

private int handleJoin(int pid, int statusAddress)

{ UserProcess process=null;

for(int i=0;i

{if(pid==childProcess.get(i).p id)

{process=childProcess.get(i);

break;}

}

if(process==null||process.thread==null)

return-1;

process.joinLock.acquire();

process.joinCondition.sleep();

process.joinLock.release();

byte[] childstat=new byte[4];

Lib.bytesFromInt(childstat, 0, process.status);

int numWriteByte= writeVirtualMemory(statusAddress,childstat);

if(process.normalExit&&numWriteByte==4)

return1;

return0;

}

private int handleExit(int status) {

coff.close();

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

{if(openfile[i]!=null)

{openfile[i].close();

openfile[i]=null;}

}

this.status=status;

normalExit=true;

if(parentProcess!=null)

{joinLock.acquire();

joinCondition.wake();

joinLock.release();

parentProcess.childProcess.remove(this);

}

unloadSections();

KThread.finish();

if(numOfRunningProcess==1)

Machine.halt();

numOfRunningProcess--;

return0;

}

1 2 3的测试

要测试系统调用和内存分配,必须创建用户程序进行测试。首先先写一个C语言的程序,然后交叉编译,编译成.coff格式的文件,这样就能在nachos下运行。运行nachos,在nachos的shell中输入测试文件名,即可执行测试程序。

这个测试程序在通过调用写好的系统调用来检测nachos系统调用的可靠性

#include"syscall.h"

#include"stdio.h"

#include"stdlib.h"

#define BUFSIZE 1024

#define BIG4096

char buf[BUFSIZE],buf2[BUFSIZE],buf3[BUFSIZE],bigBuf[BIG], bigBuf1[BIG];

int main(void)

{

//test create,close and unlink

int i,fileDescr,status,stdClose;

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

fileDescr=creat("me.txt");

if(fileDescr== -1) {

printf("Error:bad file descriptor on iteration%d", i);

return1;

}

close(fileDescr);

unlink("me.txt");

}

//test read and write

fileDescr=creat("me2.txt");

if(fileDescr ==-1){

printf("Error:could not make a file");

return1;

操作系统课程设计

课程设计报告 2015~2016学年第一学期 操作系统综合实践课程设计 实习类别课程设计 学生姓名李旋 专业软件工程 学号130521105 指导教师崔广才、祝勇 学院计算机科学技术学院 二〇一六年一月

- 1 -

- 2 -

一、概述 一个目录文件是由目录项组成的。每个目录项包含16B,一个辅存磁盘块(512B)包含32个目录项。在目录项中,第1、2字节为相应文件的外存i节点号,是该文件的内部标识;后14B为文件名,是该文件的外部标识。所以,文件目录项记录了文件内、外部标识的对照关系。根据文件名可以找到辅存i节点号,由此便得到该文件的所有者、存取权、文件数据的地址健在等信息。UNIX 的存储介质以512B为单位划分为块,从0开始直到最大容量并顺序加以编号就成了一个文件卷,也叫文件系统。UNIX中的文件系统磁盘存储区分配图如下: 本次课程设计是要实现一个简单的模拟Linux文件系统。我们在内存中开辟一个虚拟磁盘空间(20MB)作为文件存储器,并将该虚拟文件系统保存到磁盘上(以一个文件的形式),以便下次可以再将它恢复到内存的虚拟磁盘空间中。文件存储空间的管理可采用位示图方法。 二、设计的基本概念和原理 2.1 设计任务 多用户、多级目录结构文件系统的设计与实现。可以实现下列几条命令login 用户登录 logout 退出当前用户 dir 列文件目录 creat 创建文件 delete 删除文件 open 打开文件 close 关闭文件 - 3 -

read 读文件 write 写文件 mkdir 创建目录 ch 改变文件目录 rd 删除目录树 format 格式化文件系统 Exit 退出文件系统 2.2设计要求 1) 多用户:usr1,usr2,usr3,……,usr8 (1-8个用户) 2) 多级目录:可有多级子目录; 3) 具有login (用户登录)4) 系统初始化(建文件卷、提供登录模块) 5) 文件的创建:create (用命令行来实现)6) 文件的打开:open 7) 文件的读:read8) 文件的写:write 9) 文件关闭:close10) 删除文件:delete 11) 创建目录(建立子目录):mkdir12) 改变当前目录:cd 13) 列出文件目录:dir14) 退出:logout 新增加的功能: 15) 删除目录树:rd 16) 格式化文件系统:format 2.3算法的总体思想 - 4 -

操作系统课程设计实验报告

河北大学工商学院 课程设计 题目:操作系统课程设计 学部信息学部 学科门类电气信息 专业计算机 学号2011482370 姓名耿雪涛 指导教师朱亮 2013 年6月19日

主要内容 一、设计目的 通过模拟操作系统的实现,加深对操作系统工作原理理解,进一步了解操作系统的实现方法,并可练习合作完成系统的团队精神和提高程序设计能力。 二、设计思想 实现一个模拟操作系统,使用VB、VC、CB等windows环境下的程序设计语言,以借助这些语言环境来模拟硬件的一些并行工作。模拟采用多道程序设计方法的单用户操作系统,该操作系统包括进程管理、存储管理、设备管理、文件管理和用户接口四部分。 设计模板如下图: 注:本人主要涉及设备管理模块

三、设计要求 设备管理主要包括设备的分配和回收。 ⑴模拟系统中有A、B、C三种独占型设备,A设备1个,B设备2个,C设备2个。 ⑵采用死锁的预防方法来处理申请独占设备可能造成的死锁。 ⑶屏幕显示 注:屏幕显示要求包括:每个设备是否被使用,哪个进程在使用该设备,哪些进程在等待使用该设备。 设备管理模块详细设计 一、设备管理的任务 I/O设备是按照用户的请求,控制设备的各种操作,用于完成I/O 设备与内存之间的数据交换(包括设备的分配与回收,设备的驱动管理等),最终完成用户的I/O请求,并且I/O设备为用户提供了使用外部设备的接口,可以满足用户的需求。 二、设备管理函数的详细描述 1、检查设备是否可用(主要代码) public bool JudgeDevice(DeviceType type) { bool str = false; switch (type) { case DeviceType.a: {

操作系统课程设计报告书

题目1 连续动态内存管理模拟实现 1.1 题目的主要研究内容及预期达到的目标 (1)针对操作系统中内存管理相关理论进行设计,编写程序并进行测试,该程序管理一块虚拟内存。重点分析三种连续动态内存分配算法,即首次适应算法、循环首次适应算法和最佳适应算法。 (2)实现内存分配和回收功能。 1.2 题目研究的工作基础或实验条件 (1)硬件环境:PC机 (2)软件环境:Windows XP,Visual C++ 6.0 1.3 设计思想 首次适应算法的实现:从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给作业,这种方法的目的在于减少查找时间。为适应这种算法,空闲分区表中的空闲分区要按地址由低到高进行排序。该算法优先使用低址部分空闲区,在低址空间造成许多小的空闲区,在高址空间保留大的空闲区。 循环首次适应算法的实现:在分配内存空间时,不再每次从表头开始查找,而是从上次找到空闲区的下一个空闲开始查找,直到找到第一个能满足要求的的空闲区为止,并从中划出一块与请求大小相等的内存空间分配给作业。该算法能使内存中的空闲区分布得较均匀。 最佳适应算法的实现:从全部空闲区中找到能满足作业要求的、且最小的空闲分区,这种方法能使碎片尽量小。为适应此算法,空闲分区表中的空闲分区要按从小到大进行排序,从表头开始查找第一个满足要求的自由分配。 1.4 流程图 内存分配流程图,如图1-1所示。

图1-1 内存分配流程图内存回收流程图,如1-2所示。

图1-2 内存回收流程图 1.5 主要程序代码 (1)分配内存 void allocate(char z,float l) { int i,k; float ad; k=-1; for(i=0;i= l && free_table[i].flag == 1) if(k==-1 || free_table[i].length

Nachos_Project_1_2014-操作系统实验

Nachos实验项目 本实验项目采用纽约大学计算机系相关课程的实验设计。这些实验的内容以及nachos 的完整介绍请参考相关文档。 Nachos实验项目将采用分组方式完成。每4人为一组(个别组除外)。分组确定后,未经特别批准,不得变更。请各组组长在自己的起始目录下创建试验结果提交目录“nachos”(不含引号,均为小写字母)。 每次实验,我们都将指定需要提交的内容和截止时间,第一次试验的提交内容放在起始目录下的“nachos/1”目录内,第二次的放在“nachos/2”内,依次类推。请大家关注,并严格按要求操作。一个小组只要提交一份实验报告即可。对未按实验提交要求操作而造成提交失败的,将被视为实验未完成(提交内容由程序自动收集)。 从第4周起,双周的周二下午2:30~5:30为试验时间并兼做理论课程答疑时间。实验地点在404。 实验一体验Nachos下的并发程序设计 (实验指导:os_lab.ppt) 1内容简述 本次实验的目的在于对nachos进行熟悉,并初步体验nachos下的并发程序设计。实验内容分三部分:安装nachos;用C++实现双向有序链表;在nachos系统中使用你所写的链表程序并演示一些并发错误。 2实验内容(详见英文文档nachos-lab.pdf文档3.1章) 2.1安装nachos 2.2实现双向有序链表(50%) 如对c++不很熟悉,可以参考nachos-3.4/c++example/中的有关实现。 2.3体验nachos线程系统(50%) 需要做的更改有: 1)将dllist.h, https://www.doczj.com/doc/3f16187233.html,, https://www.doczj.com/doc/3f16187233.html,等文件拷贝到nachos-3.4/code/threads/目录中。 2)修改https://www.doczj.com/doc/3f16187233.html,mon中的THREAD_H、THREAD_C、THREAD_O以保证新的文件确 实被编译了。 3)根据实验内容,https://www.doczj.com/doc/3f16187233.html,,https://www.doczj.com/doc/3f16187233.html,等文件可能需要改动。 3实验结果的提交 本实验应提交的内容: https://www.doczj.com/doc/3f16187233.html,mon https://www.doczj.com/doc/3f16187233.html, https://www.doczj.com/doc/3f16187233.html, dllist.h https://www.doczj.com/doc/3f16187233.html,

操作系统课程设计实验报告(以Linux为例)

《操作系统课程设计》 实验报告 学号: 姓名: 苏州大学计算机科学与技术学院 2014年9月

操作系统课程设计实验报告 目录 目录 (1) 一、实验环境 (2) 二、实验报告总体要求 (2) 实验一编译L INUX内核 (3) 实验二观察L INUX行为 (7) 实验三进程间通信 (14)

操作系统课程设计实验报告 一、实验环境 Linux平台 ◆硬件平台:普通PC机硬件环境。 ◆操作系统:Linux环境,例如,红旗Linux或Red Hat Linux;启动 管理器使用GRUB。 ◆编译环境:伴随着操作系统的默认gcc环境。 ◆工作源码环境:一个调试的内核源码,版本不低于2.4.20。 二、实验报告总体要求 在2013年11月25日前提交实验报告。实验报告至少要求包含以下内容: 1.引言:概述本次实验所讨论的问题,工作步骤,结果,以及发现的意 义。 2.问题提出:叙述本篇报告要解决什么问题。注意不可以抄写实验要求 中的表述,要用自己的话重新组织我们这里所提出的问题。 3.解决方案:叙述如何解决自己上面提出的问题,可以用小标题 3.1, 3.2<等分开。这是实验报告的关键部分,请尽量展开来写。注意, 这部分是最终课程设计的基本分的部分。这部分不完成,本课程设计不会及格。 4.实验结果:按照自己的解决方案,有哪些结果。结果有异常吗?能解 释一下这些结果吗?同别人的结果比较过吗?注意,这部分是实验报告出彩的地方。本课程设计要得高分,应该在这部分下功夫。 5.结束语:小结并叙述本次课程设计的经验、教训、体会、难点、收获、 为解决的问题、新的疑惑等。 6.附录:加了注释的程序清单,注释行数目至少同源程序行数目比1: 2,即10行源程序,至少要给出5行注释。

操作系统课程设计报告

操作系统课程设计报告

东莞理工学院 操作系统课程设计报告 学院:计算机学院 专业班级: 13软件工程1班 提交时间: 2015/9/14 指导教师评阅意见: . 项目名称:进程与线程管理功能 一、设计目的 用语言来模拟进程和线程管理系统,加深对进程和线程的理解,掌握对进程和线程各种状态和管理的算法原理。

二、环境条件 系统: WindowsXP、VMWare、Ubuntu Linux 语言:C/C++ 开发工具:gcc/g++、Visual C++ 6.0 三、设计内容 1. 项目背景 计算机的硬件资源有限,为了提高内存的利用率和系统的吞吐量,就要根据某种算法来管理进程和线程的状态从而达到目的。 进程与线程管理功能完成基于优先级的抢占式线程调度功能,完成进程虚拟内存管理功能。 进程与线程管理功能 基本要求:完成基于优先级的抢占式线程调度功能,完成进程虚拟内存管理功能。 提高要求:(增加1项就予以加分) (1) 实现多种线程调度算法; (2)通过“公共信箱”进行通信的机制,规定每一封信的大小为128字节,实现两个用户进程之间通过这个“公共信箱”进行通信。 (3) 实现多用户进程并发的虚拟内存管理功能。

(4) 实现用户进程间通信功能,并用生产者/消费者问题测试进程间通信功能的正确性。 (5) 实现改进型Clock页面置换算法。 (6) 实现Cache功能,采用FIFO替换算法。 2. 扩展内容 实现多种线程调度算法:时间片轮转调度算法 四、人员分工 优先级调度算法:钟德新,莫友芝 时间片轮转调度算法:张德华,袁马龙 设计报告由小组队员共同完成。小组成员设计的代码分工如下:钟德新编写的代码:void Prinft(){ PCB *p; system("cls");//清屏 p=run; //运行队列 if(p!=NULL) { p->next=NULL; } cout<<"当前正在运行的进程:"<procname<<"\t\t"<pri<<"\t"<needOftime<<"\t\t"<runtime<<"\t\t"<state<next; } cout<

Nachos实验报告9

计算机科学与技术学院实验报告:9 实验题目:设计并实现具有优先级的线程调度策略姓名:李威 日期:2013-12-1 学号:201100300259 班级:11级软件3班Email:sduliwei@https://www.doczj.com/doc/3f16187233.html, 实验目的: Nachos系统采用基本的FCFS的线程调度策略,修改成为具有优先级的线程调度策略 硬件环境: 软件环境: linux操作系统,Nachos操作系统 实验步骤: 1.修改Thread类的构造函数,加入优先级priority属性,并且加入getPrioty方法。以便在线程的 等待队列中找到优先级最高的线程。其中,线程优先级的范围从1到7,默认为7,即最低优先级。 修改代码如下:(https://www.doczj.com/doc/3f16187233.html,,thread.h) class Thread { …………………………………… public: Thread(char* debugName, int priority=7);// initialize a Thread ………………………………………………… int getPriority(){return this->priority; } Thread::Thread(char* threadName, int p) { if(p<1) priority = 1; else if(p>7) priority = 7; else priority = p; name = threadName; stackTop = NULL; stack = NULL; status = JUST_CREATED; #ifdef USER_PROGRAM space = NULL; #endif } 2,首先,了解Nachos系统原来的线程调度方式。通过读https://www.doczj.com/doc/3f16187233.html,,https://www.doczj.com/doc/3f16187233.html,,https://www.doczj.com/doc/3f16187233.html,文件 中的内容了解线程调度的方式。

操作系统课程设计报告

上海电力学院 计算机操作系统原理 课程设计报告 题目名称:编写程序模拟虚拟存储器管理 姓名:杜志豪.学号: 班级: 2012053班 . 同组姓名:孙嘉轶 课程设计时间:—— 评语: 成绩: 目录 一、设计内容及要求 (4) 1. 1 设计题目 (4) 1.2 使用算法分析: (4)

1. FIFO算法(先进先出淘汰算法) (4) 1. LRU算法(最久未使用淘汰算法) (5) 1. OPT算法(最佳淘汰算法) (5) 分工情况 (5) 二、详细设计 (6) 原理概述 (6) 主要数据结构(主要代码) (6) 算法流程图 (9) 主流程图 (9) Optimal算法流程图 (10) FIFO算法流程图 (10) LRU算法流程图 (11) .1源程序文件名 (11) . 2执行文件名 (11) 三、实验结果与分析 (11) Optimal页面置换算法结果与分析 (11) FIFO页面置换算法结果与分析 (16) LRU页面置换算法结果与分析 (20) 四、设计创新点 (24) 五、设计与总结 (27)

六、代码附录 (27) 课程设计题目 一、设计内容及要求 编写程序模拟虚拟存储器管理。假设以M页的进程分配了N

块内存(N

nachos Lab7实习报告

shell实现实习报告 页脚内容1

目录 内容一:总体概述 (3) 内容二:任务完成情况 (3) 任务完成列表(Y/N) (3) 具体Exercise的完成情况 (4) 内容三:遇到的困难以及解决方法 (19) 内容四:收获及感想 (20) 内容五:对课程的意见和建议 (20) 内容六:参考文献 (20) 页脚内容2

内容一:总体概述 本次实习需要实现用户程序shell。shell是提供使用者使用界面的软件(命令解析器),他接收用户命令,然后调用相应的应用程序。本次shell实现的基础是前面已经完成的相关功能。注意到nachos已经实现简单的shell,我们只需要在此基础上进行相关的修改。 内容二:任务完成情况 任务完成列表(Y/N) 页脚内容3

具体Exercise的完成情况 设计实现一个用户程序shell,通过./nachos -x shell进入用户交互界面中。在该界面中可以查询支持的功能、可以创建删除文件或目录、可以执行另一个用户程序并输出运行结果,类似Linux上跑的bash。你实现的越完善,碰到的问题越多,学到的也会越多。 本实验所修改的代码包括内核和用户程序两部分。 首先,需要解析输入的命令,这部分现有程序已经完成 Write(prompt, 2, output); Read(&buffer[i], 1, input); 因为在Lab6中,我没有考虑标准输入和标准输出的问题,所以需要修改https://www.doczj.com/doc/3f16187233.html,处理read系统调用和处理write系统调用的部分 针对处理read系统调用的部分,如果系统调用的第3个参数是0(表示标准输入),那么读取从用户界面输入的字符串存入相应的位置 if(fd == 0){ for (int i = 0; i < count; i++) content[i] = getchar(); } 针对处理write系统调用的部分,如果系统调用的第3个参数是1(表示标准输出),那么输出缓冲区 页脚内容4

操作系统课程设计论文

学年论文(课程设计)题目:操作系统课程设计 学院数学与计算机学院 学科门类工学 专业网络工程 学号 姓名 指导教师王煜 年月日

河北大学学年论文(课程设计)任务书 (指导教师用表) 指导教师签字: 系主任签字: 主管教学院长签字: 装 订 线

河北大学学年论文(课程设计)成绩评定表学院:数学与计算机学院 装 订 线

摘要 此系统实现了存储管理、设备管理和进程管理。 存储管理部分主要实现主存空间的分配和回收。存储管理采用可移动的可变分区存储管理方式。采用数组来模拟主存,大小为512个字节。 设备管理主要包括设备的分配和回收。模拟系统中有A、B、C三种独占型设备,A设备3个,B设备2个,C设备1个。设备分配时采用采用先来先服务策略。设备回收时唤醒等待设备的进程。 进程管理主要包括进程调度,进程的创建和撤销、进程的阻塞和唤醒,中断作用的实现。其中硬件中的中央处理器用不断循环的函数CPU( )模拟,重要寄存器(如:程序状态寄存器PSW、指令寄存器IR)用全局变量模拟,中断的发现是在函数CPU中加检测PSW 的方式来模拟,时钟的模拟通过timer控件实现。进程控制块的模拟通过数组,本系统最多容纳10个。进程调度时采用时间片轮转调度算法,时间片为5。 关键词:存储管理设备管理进程管理时间片

ABSTRACT The system has storage management, equipment management and process management. The storage management has achieved the allocation and recovery of the main memory space. Variable storage management is used as storage management .We simulate the main memory by array, whose size is 512 bytes. The device management, including the distribution and recovery of devicet. We simulate three devices ,A,B,C. the numbers of them are 3,2,1. The distribution of device used to adopt first-come first-service strategy. It awakes the blocking process when the device is recycled. The process management, including scheduling ,creating revocation ,blocking and waking up the process, the realization of the interruption.We simulate the central processing unit by the cycling function named CPU(),simulate the important register by global variable, simulate the recovering of interruption by checking PSW in the function of CPU(),simulate the clock by the timer control. The simulation of the process control block by array, whose number is up to 10. When the scheduling of the process happens, we use the algorithm of time piece rotation scheduling, and the time piece is 5. Key words: storage device process time

操作系统课程设计报告

东莞理工学院 操作系统课程设计报告学院:计算机学院 专业班级:13软件工程1班 提交时间:2015/9/14 指导教师评阅意见: . 项目名称:进程与线程管理功能 一、设计目的 用语言来模拟进程和线程管理系统,加深对进程和线程的理解,掌握对进程和线程各种状态和管理的算法原理。 二、环境条件 系统:WindowsXP、VMWare、Ubuntu Linux 语言:C/C++ 开发工具:gcc/g++、Visual C++ 6.0 三、设计内容 1. 项目背景

计算机的硬件资源有限,为了提高内存的利用率和系统的吞吐量,就要根据某种算法来管理进程和线程的状态从而达到目的。 进程与线程管理功能完成基于优先级的抢占式线程调度功能,完成进程虚拟内存管理功能。 进程与线程管理功能 基本要求:完成基于优先级的抢占式线程调度功能,完成进程虚拟内存管理功能。 提高要求:(增加1项就予以加分) (1) 实现多种线程调度算法; (2)通过“公共信箱”进行通信的机制,规定每一封信的大小为128字节,实现两个用户进程之间通过这个“公共信箱”进行通信。 (3) 实现多用户进程并发的虚拟内存管理功能。 (4) 实现用户进程间通信功能,并用生产者/消费者问题测试进程间通信功能的正确性。 (5) 实现改进型Clock页面置换算法。 (6) 实现Cache功能,采用FIFO替换算法。 2. 扩展内容 实现多种线程调度算法:时间片轮转调度算法 四、人员分工 优先级调度算法:钟德新,莫友芝 时间片轮转调度算法:张德华,袁马龙 设计报告由小组队员共同完成。小组成员设计的代码分工如下: 钟德新编写的代码:void Prinft(){ PCB *p; system("cls");//清屏 p=run; //运行队列 if(p!=NULL) { p->next=NULL; } cout<<"当前正在运行的进程:"<procname<<"\t\t"<pri<<"\t"<needOftime<<"\t\t"<runtime<<"\t\t"<state<next; } cout<procname<<"\t\t"<pri<<"\t"<needOftime<<"\t\t"<runtime<<"\t\t"<state<next; } cout<

nachos实验七实验报告

nachos实验报告七 实验题目: Extension of AddrSpace 学号:201200301057 日期:2014-11-29 班级:计软12-3 姓名:高鹏辉 实验目的: 在了解了Nachos 装入并执行单个用户进程的情况后,我们就需要进一步完成用户内存空间的扩充以便多用户程序同时驻留内存,进而使多用户进程并发执行。 硬件环境: Mem:3.9G CPU:Intel? Core?2 Quad CPU Q9500 @ 2.83GHz × 4 Disk:15.5 GB 软件环境: System:ubuntu12.04LST i386 gcc: (Ubuntu 4.6.3-1ubuntu5) 4.6.3 nachos system 实验步骤: 要在Nachos中实现多用户程序同时驻留内存并发执行,首先涉及到Nachos的两个系统调用:Exec()和Exit()。这两个系统调用也是构造父子进程并发执行的基础。假设我们有以下两个用户程序:../test/exec.c和../test/halt.c ../test/halt.c 第65页 用户进程管理设计 1 #include "syscall.h" 2 int 3 main() 4 { 5 Halt() 6 } ../test/exec.c 1 #include "syscall.h" 2 int 3 main() 4 { 5 SpacId pid; 6 pid = Exec("../test/halt.noff");

7 Halt() 8 } 在文件../test/exec.c第5行上的语句Exec是一条Nachos的系统功能调用,它的功能为装入并执行以其参数为名的可执行文件,即创建一个新的用户进程。假设我们先执行../test/exec.noff 程序,则../test/exec.noff 会在它还没有执行结束时又装入并执行另外一个程序halt.noff,并与它同时驻留内存. pageTable[i].physicalPage=usermap-->Find();避免从头开始物理存储覆盖了前一个用户程序的内存内容 利用Nachos在../userprog/bitmap.h 中文件定义的Bitmap类。利用bitmap 记录和申请内存物理帧,使不同的程序装入到不同的物理空间中去,下面是对新的内存分配存储算法,改进了对多个用户程序的同时进驻内存的支持

期末 操作系统实验课程设计

操作系统实验课程设计(二)(参照实验五) 学院:计算机科学与工程专业:信息管理工作与信息系统学号:2008142118 姓名:丁建东 一、实验题目:设计一个Shell解释器 二、实验目的:本设计的主要目的在于学会如何在Unix系 统下创建进程和管理进程。 三、实验内容: 实现一个简单的shell(命令行解释器),类似于bash, csh等。 要求实现的shell支持以下内部命令: 1.cd <目录> 更改当前的工作目录到另一个<目录>。如果<目录>未指定,输出当前工作目录。如果<目录>不存在,要求有适当的错误信息提示。改命令应能够改变PWD的环境变量。 2.echo <内容> 显示echo后的内容且换行。 3.help 简短概要地输出你的shell的使用方法和基本功能。 4.jobs

输出shell当前的一系列子进程,要求提供子进程的命名和PID号。 5.quit, exit, bye 退出shell。 所有的内部命令应当优于在$PATH中同名的程序。 任何非内部命令必须请求shell创建一个新进程,且该子进程执行指定的程序。这个新进程必须继承shell的环境变量和指定的命令行参数。 要求实现的shell支持以下内部命令: Batch Processing 如果shell启动带有一个文件名作为参数,打开该文件并执行文件里所有命令。待所有进程全部结束退出shell。 四、实验思路: 1.所用到的系统函数 (1)打开目录 void cd() API调用:int chdir(dir);getcwd(dir,dir_max); 实现:改变当前目录,并判断目录是否存在。 (2)回应 void echo() 实现: 用户输入字符串,以回车结束输入。

操作系统课程设计报告

东莞理工学院 操作系统课程设计报告 学院:计算机学院 专业班级:13软件工程1班 提交时间:2015/9/14 指导教师评阅意见: . 项目名称:进程与线程管理功能 一、设计目的 用语言来模拟进程和线程管理系统,加深对进程和线程的理解,掌握对进程和线程各种状态和管理的算法原理。 二、环境条件

系统:WindowsXP、VMWare、Ubuntu Linux 语言:C/C++ 开发工具:gcc/g++、Visual C++ 6.0 三、设计内容 1. 项目背景 计算机的硬件资源有限,为了提高内存的利用率和系统的吞吐量,就要根据某种算法来管理进程和线程的状态从而达到目的。 进程与线程管理功能完成基于优先级的抢占式线程调度功能,完成进程虚拟内存管理功能。 进程与线程管理功能 基本要求:完成基于优先级的抢占式线程调度功能,完成进程虚拟内存管理功能。 提高要求:(增加1项就予以加分) (1) 实现多种线程调度算法; (2)通过“公共信箱”进行通信的机制,规定每一封信的大小为128字节,实现两个用户进程之间通过这个“公共信箱”进行通信。 (3) 实现多用户进程并发的虚拟内存管理功能。 (4) 实现用户进程间通信功能,并用生产者/消费者问题测试进程间通信功能的正确性。 (5) 实现改进型Clock页面置换算法。 (6) 实现Cache功能,采用FIFO替换算法。

2. 扩展内容 实现多种线程调度算法:时间片轮转调度算法 四、人员分工 优先级调度算法:钟德新,莫友芝 时间片轮转调度算法:张德华,袁马龙 设计报告由小组队员共同完成。小组成员设计的代码分工如下:钟德新编写的代码:void Prinft(){ PCB *p; system("cls");//清屏 p=run; //运行队列 if(p!=NULL) { p->next=NULL; } cout<<"当前正在运行的进程:"<procname<<"\t\t"<pri<<"\t"<needOftime<<"\t\t"<runtime<<"\t\t"<state<next; } cout<procname<<"\t\t"<pri<<"\t"<needOftime<<"\t\t"<runtime<<"\t\t"<state<next; } cout<procname<<"\t\t"<pri<<"\t"<needOftime<<"\t\t"<runtime<<"\t\t"<state<

nachos01

实验一体验Nachos下的并发程序设计 一、小组成员及分工 汪于波(23020078104116):https://www.doczj.com/doc/3f16187233.html,的修改、https://www.doczj.com/doc/3f16187233.html,的修改和实验报告 潘羽龙(23020078104100):https://www.doczj.com/doc/3f16187233.html,的实现 吴道裕(23020078104132):https://www.doczj.com/doc/3f16187233.html,的实现和实验报告的完成 谭原(23020078104111):dllist.h的实现和https://www.doczj.com/doc/3f16187233.html,mon的修改 二、实验目的 对nachos进行熟悉,并初步体验nachos下的并发程序设计。 三、实验内容 1.安装nachos; 2.用C++实现双向有序链表; 3.在nachos系统中使用你所写的链表程序并演示一些并发错误 四、实验步骤 1.首先明确Nachos各部分的关系 在~/nachos/nachos-3.4/code/下有一个https://www.doczj.com/doc/3f16187233.html,mon,在code/的各个子目录下的Makefile都继承这个https://www.doczj.com/doc/3f16187233.html,mon。通过阅读https://www.doczj.com/doc/3f16187233.html,知道,main函数一旦启动,立即调用Initialize,进行初始化的操作,然后对相应的参数进行处理,之后在分模块进行相应模块下的函数调用,执行相应的功能。 2.编写相应的函数 实验要求利用对双向链表的操作来演示并发程序可能出现的错误,首先需要实现双向链表dllist,包括dllist.h,https://www.doczj.com/doc/3f16187233.html,。当DLList类实现后,需要编写链表驱动函数Insert 和Remove来对链表进行驱动。通过改写https://www.doczj.com/doc/3f16187233.html,,使得多个线程在没有进行任何互斥操作的情况下对同一数据结构进行操作,在这个过程中就可能出现并发错误。改写https://www.doczj.com/doc/3f16187233.html,mon和https://www.doczj.com/doc/3f16187233.html,。 3.详细设计 a)dllist.h(~/nachos/nachos-3.4/code/threads/) 类DLList的声明 class DLLElement { public: DLLElement(void *itemPtr,int sortKey);//initialize a list element DLLElement *next;//next element on list DLLElement *prev;//previous element on list int key; void *item; }; class DLList { public: DLList();//initialize the list DLList(int type); ~DLList();//de-allocate the list

操作系统(一个小型操作系统的设计与实现)课程设计

南通大学计算机科学与技术学院操作系统课程设计报告 专业: 学生姓名: 学号: 时间:

操作系统模拟算法课程设计报告 设计要求 将本学期三次的实验集成实现: A.处理机管理; B.存储器管理; C.虚拟存储器的缺页调度。 设计流程图 主流程图 开始的图形界面 处理机管理存储器管理缺页调度 先来先服务时 间 片 轮 转 首 次 适 应 法 最 佳 适 应 法 先 进 先 出 L R U 算 法

A.处理机调度 1)先来先服务FCFS N Y 先来先服务算法流程 开始 初始化进程控制块,让进程控制块按进程到达先后顺序让进程排队 调度数组中首个进程,并让数组中的下一位移到首位 计算并打印进程的完成时刻、周转时间、带权周转时间 其中:周转时间 = 完成时间 - 到达时间 带权周转时间=周转时间/服务时间 更改计时器的当前时间,即下一刻进程的开始时间 当前时间=前一进程的完成时间+其服务时间 数组为空 结束

2)时间片轮转法 开始 输入进程总数 指针所指的进程是 否结束 输入各进程信息 输出为就绪状态的进程的信息 更改正在运行的进程的已运行时间 跳过已结束的程序 结束 N 指向下一个进程 Y 如果存在下一个进程的话 Y N 输出此时为就绪状态的进程的信息 时间片轮转算法流程图

B.存储器管理(可变式分区管理) 1)首次适应法 分配流程图 申请xkb内存 由链头找到第一个空闲区 分区大小≥xkb? 大于 分区大小=分区大小-xkb,修改下一个空闲区的后向指针内容为(后向指针)+xkb;修改上一个空闲区的前向指针为(前向指针)+xkb 将该空闲区从链中摘除:修改下一个空闲区的后向地址=该空闲区后向地址,修改上一个空闲区的前向指针为该空闲区的前向指针 等于 小于延链查找下 一个空闲区 到链尾 了? 作业等待 返回是 否 登记已分配表 返回分配给进程的内存首地址 开始

操作系统课程设计实验报告proj2

操作系统课程设计报告 班级: 团队成员:

目录 ................................................................................................................ 错误!未定义书签。 一、实验要求:建立线程系统................................................................... 错误!未定义书签。 1.1Task 2.1实现文件系统调用 (3) 1.1.1题目要求 (3) 1.1.2题目分析与实现方案 (3) 1.1.3关键点与难点 (4) 1.1.4实现代码 (4) 1.2 Task 2.2 完成对多道程序的支持 (5) 1.2.1题目要求 (5) 1.2.2题目分析与实现方案 (5) 1.2.3关键点与难点 (6) 1.2.4实现代码 (7) 1.3 Task 2.3 实现系统调用 (7) 1.3.1题目要求 (7) 1.3.2题目分析与实现方案 (8) 1.3.3关键点与难点 (9) 1.3.4实现代码 (9) 1.4 Task 2.4 实现彩票调度 (10) 1.4.1题目要求 (10) 1.4.2题目分析与实现方案 (10) 1.4.3关键点与难点 (11) 1.4.4实现代码 (11) 二、测试结果............................................................................................ 2错误!未定义书签。

操作系统课程设计报告

操作系统课程设计实验报告 实验名称:进程控制 姓名/学号: 一、实验目的 学习、理解和掌握Linux与windows的进行控制系统调用的功能,熟悉主要的几个系统调用命令的格式和如何利用系统调用命令进行编程。通过学习,理解如何创建一个进程、改变进程执行的程序、进程和线程终止以及父子进程的同步等,从而提高对进程和线程控制系统调用的编程能力。 二、实验内容 设计并实现Unix的“time”命令。“mytime”命令通过命令行参数接受要运行的程序,创建一个独立的进程来运行该程序,并记录程序运行的时间。 三、实验环境 CPU: Inter ×2 2.10GHz RAM: 3.00GB Windows 7 旗舰版 Linux Ubuntu 10.04 编译: VS2010 四、程序设计与实现 4.1进程控制系统的调用 4.1.1 windows进程控制调用程序中使用的数据结构及主要符号说明 SYSTEMTIME starttime,endtime; //进程开始时间和结束时间 PROCESS_INFORMATION pi //该结构返回有关新进程及 //其主线程的信息 STARTUPINFO si //该结构用于指定新进程的主窗口特性4.1.2 linux进程控制调用程序中使用的数据结构及主要符号说明 struct timeval starttime,endtime //进程开始时间和结束时间 pid_t pid //进程标志符

4.2 程序流程图 图1 windows进程控制调用图2 linux进程控制调用程序运行流程图程序运行流程图 五、实验结果和分析 5.1 windows实验结果和分析

相关主题
文本预览
相关文档 最新文档