:由于老师一直没发实验报告模板,所以直到今天才开始写,本次实验是延续上一次实验所做,并会对上一次实验中的某些过程进行修改(不理解的同学可以看一下上一篇博客)!!!

实验目的

(1)通过阅读相关源码,掌握NachOS调度的数据结构和实现过程;
(2)对NachOS线程描述进行完善,增加关于调度的内容;
(3)掌握NachOS线程调度的算法。

实验内容

(1)在NachOS线程描述中增加调度优先级的数据成员,并完善就绪队列管理的成员方法;
(2)实现基于优先级的FCFS调度。

实验过程

这次试验也是看了许多网上的方法,最后根据自己的能力写了一个自己能理解的方法,那就是:线程在进入后序队列时进行修改,让优先级高的线程排在优先级低的线程前面。

线程被调进就绪队列是在Yield函数(位置:thread.cc)中被调用:

kernel->scheduler->ReadyToRun(this); //将当前线程加入就绪队列

void
Thread::Yield ()
{Thread *nextThread;IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);  //关中断ASSERT(this == kernel->currentThread);  DEBUG(dbgThread, "Yielding thread: " << name);nextThread = kernel->scheduler->FindNextToRun();//找到下一个要运行的线程并使nextThrad指向它if (nextThread != NULL) {kernel->scheduler->ReadyToRun(this); //将当前线程加入就绪队列kernel->scheduler->Run(nextThread, FALSE); //运行下一个线程}(void) kernel->interrupt->SetLevel(oldLevel);
}

所以需要转到scheduler.cc中查看:scheduler->ReadyToRun

void
Scheduler::ReadyToRun (Thread *thread)
{ASSERT(kernel->interrupt->getLevel() == IntOff);DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());thread->setStatus(READY);       //将线程状态置为就绪态readyList->Append(thread);     //将线程加入就绪队列的队尾
}

所我们就可以参照 Append() (位置:list.cc)方法的结构,自己写一个根据优先级插入的方法,线程在进入后序队列时,让优先级高的线程排在优先级低的线程前面。对于 Append() 函数的结构大家就自己去查看就好,下面就直接阐述实现的过程。

实现过程:
(1)因为Append() 函数是list.cc中的函数,所以我们自己写插入函数的时候,也应该是在list.cc中实现,在这之前需要在list.h中声明一下:
void Newsort(T item,int priority);

template <class T>
class List {public:List();                     // initialize the listvirtual ~List();            // de-allocate the listvirtual void Prepend(T item);// Put item at the beginning of the listvirtual void Append(T item); // Put item at the end of the list
//----------------------------------------------------------------------------------------修改处--调度实验void Newsort(T item,int priority);  //创建一个方法  对要传入就绪队列的线程排序插入(根据优先级的高低)//----------------------------------------------------------------------------------------T Front() { return first->item; }

(2)然后就可以在list.cc中实现这个方法了(在这个函数中:priority值越大,则优先级越高):

//------------------------------------------------------------------修改处---实现list.h中的方法
template <class T>
void
List<T>::Newsort(T item, int priority)  // item-->当前线程  priority-->当前线程的优先级
{ListElement<T> *element = new ListElement<T>(item);  //创建的一个以 item 为核心的节点 ASSERT(!IsInList(item));   //当要加入的线程已经在队列中时就打断运行,并输出报错信息if(IsEmpty())  //当队列为空时,就直接将当前的 item 放在里面 {Prepend(item);   // 将其放在最后面 ,因为是空的,所以最后最前都是一样的 }else{//当不为空时,则按照优先级值的大小进行插入 (类似于学数据结构时的链表的插入) ListElement<T> *prev = first;   //定义一个指针指向头节点first ListElement<T> *ptr = NULL;   //定义一个指针先放空, 用于后面插入的时候,记录前一个节点的位置 while(prev != NULL) //即当该节点不为空时,节点会不断向后移动,当移到最后一个节点的后面时就为空 {if(priority > prev->item->priority)   //当当前线程的优先级大于指针指向的节点的优先级时 {element->next = prev;   //当前线程的尾指针指向 prev if(ptr == NULL)first = element;//当当前队列中:当前线程的优先级是最高时,头节点直接指向它 elseptr->next = element;//如果ptr不为空,则ptr记录了上一个节点的位置,//则将上一个节点的尾指针指向当前线程             numInList++; //队列中的元素个数加1         break;}ptr = prev;   //ptr记录当前指针的位置 prev = prev->next;  // prev向下移动一个节点 }if(ptr == last)   //如果ptr记录的已经为最后一个节点了,则说明当前线程的优先级是队列中最低的 {                                                                       //直接将它插入到最后面Append(item);                                                                                                                                }}
}
//-------------------------------------------------------------------------------------------

(3)方法已经实现了,那我们就可以使用这个方法了,方法应该要在哪里使用呢?之前的 Append() 函数是在scheduler->ReadyToRun(位置:scheduler.cc)中使用的,所以新创建的这个方法也在scheduler->ReadyToRun中使用就可以了,当然对其进行了一定的修改:

void
Scheduler::ReadyToRun (Thread *thread)
{ASSERT(kernel->interrupt->getLevel() == IntOff);DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());thread->setStatus(READY);       //将线程状态置为就绪态
//------------------------------------------------------------------------------------------ -修改处
//    readyList->Append(thread);     //将线程加入就绪队列的队尾-----------将原来的这句注释掉if(readyList->IsEmpty())    //如果就绪队列是空时{                              //  直接将当前线程加队尾(这里队尾和队头都是一样的,因为里面是空的)readyList->Append(thread); return;               }readyList->Newsort(thread, thread->priority);   //不为空时调用自己写的函数,参数为:当前线程、优先级值//------------------------------------------------------------------------------------------------
}

:当我们这些条件都准备好后,就可以对thread.cc进行修改了。因为这次实验是在上一次实验基础做的,所以对于上一次实验的部分不在阐述,重新修改的地方将会用 //*************** 指明。

(4)首先对原构造函数Thread::Thread(char* threadName) (位置:thread.cc)
进行修改,将main线程和postal worker线程的优先级进行置为最高10000;将ping线程的优先级置为-1;将里面的输出语句注释掉,输出语句我们放到测试函数中去实现。

Thread::Thread(char* threadName)
{//--------------------------------------------------------------------------------------修改处if(++threadNUM>=MAX_SIZE){                    //当线程数大于规定的最大线程数时,输出最大线程数,并打断程序执行cout<<"最大线程数:"<<MAX_SIZE<<endl;ASSERT(threadNUM<=MAX_SIZE);}int i=0;for(i=0;i<MAX_SIZE;i++){    //每次创建一个新的线程,这里便要从0开始检查,直到到达未被使用的线程号为止if(Tstatus[i]==0){    //如果线程号未被使用,便执行以下操作this->tid=i+1;    //  给线程赋上一个id号, 因为是从0开始计算,所id号需要加1srand(time(0)+i);    //设置一个随机种子         this->priority=rand()%(100);  //给每个线程附加一个随机的优先级值Tstatus[i]=1;       //将该线程号状态置为1,表示已经被使用了break;}}
//************************************************************************************************修改处if(strcmp(threadName,"main")==0||strcmp(threadName,"postal worker")==0)this->priority =10000;if(strcmp(threadName,"ping")==0)this->priority=-1;
//***********************************************************************************************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;
//*****************************************************************************************************修改处---将上一次实验的修改处注释掉
//--------------------------------------------------------------------------修改处
//      cout<<"线程名:"<<this->getName()<<"    线程id:"<<this->getid()<<"    线程优先级:"<<this->priority<<endl;//输出线程一系列参数:名字、id、优先级。
//-------------------------------------------------------------------------------
}

(5)对析构函数Thread::~Thread()(位置:thread.cc)进行修改:

Thread::~Thread()
{DEBUG(dbgThread, "Deleting thread: " << name);
//---------------------------------------------------------------------------修改处Tstatus[tid-1]=0;     //将该线程号的状态置0,即被释放了之后,该线程号可以被其他线程使用threadNUM--;       //  将现在线程的总数减1//-----------------------------------------------------------------------------ASSERT(this != kernel->currentThread);if (stack != NULL)DeallocBoundedArray((char *) stack, StackSize * sizeof(int));
}

(6)对测试函数Thread::SelfTest()(位置:thread.cc)进行修改:

void
Thread::SelfTest()
{DEBUG(dbgThread, "Entering Thread::SelfTest");
//-----------------------------------------------------------------------修改处--以下部分为原代码被注释掉
/*    Thread *t = new Thread("forked thread");t->Fork((VoidFunctionPtr) SimpleThread, (void *) 1);kernel->currentThread->Yield();SimpleThread(0);
*/
//************************************************************修改处---将第一次修改的部分注释掉
//------------------------------------------------------------------修改处-/*      Thread *t[124];   //定义一个大小为124的线程数组,因为在程序运行中会产生另外4个线程,1个main线程// 1个postal worker 线程,2个ping线程,所以这里创建124个线程正好满足128个线程for(int i = 0;i < 124;i++){t[i] = new Thread("线程");}       */
//------------------------------------------------------------------------
//******************************************************************修改处---添加本次的修改处Thread *t[5];for(int i=0;i<5;i++){t[i]= new Thread("New Thread");cout<<"线程名: "<< t[i]->getName()<<"   线程ID: "<< t[i]->getid()<<"   优先级: "<<t[i]->getPriority()<<endl;if(i==4) cout<<endl;t[i]->Fork((VoidFunctionPtr)SimpleThread,(void *)t[i]);}
}

(7)注:我们在修改的测试函数中SimpleThread,(void *)t[i]), 参数变为了 t[i] ,所以下面我们修改SimpleThread (int which) (位置:thread.cc)函数时需要对其参数一并修改:

static void
SimpleThread(Thread *t)     //将这里的参数类型变为 Thread类型
{int num;for (num = 0; num < 2; num++) {  //这里就只运行2次便于观察cout<<"线程名: "<<t->getName()<<"   线程ID:"<<t->getid()<<"   优先级: "<<t->getPriority()<<"   lopped: "<<num<<"   times"<<endl;kernel->currentThread->Yield();}
}

(8)改到这里就以基本完成了,但你这个时候去运行就会发现会报错,这是因为priority是一个私有变量,无法传递到某些类中去使用,所以就必须将它变为公开的变量,这就需要到 thread.h 中进行修改(这里将 tid 一并转移到了公开区域),同时创建了一个getPriority() 函数:

class Thread {private:// NOTE: DO NOT CHANGE the order of these first two members.// THEY MUST be in this position for SWITCH to work.int *stackTop;                       // the current stack pointervoid *machineState[MachineStateSize];  // all registers except for stackTop
//*******************************************************************将私有变量 priority和 tid 注释掉
//------------------------------------------------------------------------------修改处
//      int tid;   //定义每一个线程的id号
//      int priority;    //定义每个线程的优先级//因为每个线程的id和由优先级都是独有的,所以定义在私有变量
//--------------------------------------------------------------------------------public:Thread(char* debugName);            // initialize a Thread ~Thread();                          // deallocate a Thread// NOTE -- thread being deleted// must not be running when delete // is called// basic thread operations
//*************************************************修改处---将上面两个变量定义到公开区域,同再创建一个getPriority() 函数
//---------------------------------------------------------------------------修改处int tid;   //定义每一个线程的id号int priority;    //定义每个线程的优先级int  getid(){return this->tid;}     //返回该线程的id号int getPriority(){ return this->priority;}       //返回新构造函数的优先级值
//--------------------------------------------------------------------------

这样就完成了所有的修改,下面是实验运行的结果:

注1:由于使用的是原构造函数,所以就会有main线程和postal worker线程的出现,但是我们将原构造函数中的输出语句放到了测试函数中,所以就不会输出这两个线程的一系列参数,但是它们是存在的,所以最后输出的ID号是从3开始的,但不影响结果,写好注释说明即可。

注2:实验环境:Ubuntu14.04。

写的不是很好,大家就将就看一下,有错误的地方大家多多包涵。
最后希望大家早日完成实验报告,少熬夜。

NachOS根据优先级的线程调度实验相关推荐

  1. 操作系统NACHOS实验(二)具有优先级的线程调度

    操作系统NACHOS实验(二)具有优先级的线程调度 实验思路 关键源代码注释及说明 调试记录 可能会有一些小错误,但是基本思路应该还是没问题的. 实验思路 首先找到控制线程调度的代码 schedule ...

  2. 操作系统课设--具有优先级的线程调度

    山东大学操作系统课设lab2 实验二 具有优先级的线程调度(lab2) 概念欠缺 实验环境 实验目的 1. 熟悉Nachos原有的线程调度策略 2. 设计并实现具有优先级的线程调度策略 实验二 具有优 ...

  3. VRRP配置上联口down时,优先级减10实验配置步骤

    实验拓扑图: 实验配置思路: 配置VRRP上联口down时,优先级减10 实验摘要重点命令: [zhu]interface g0/0/0 [zhu-GigabitEthernet0/0/1]vrrp ...

  4. Nachos实习——Lab1线程机制实习报告

    Nachos实习--Lab1线程机制实习报告 文章目录 Nachos实习--Lab1线程机制实习报告 内容一:总体概述 内容二:任务完成情况 内容三:具体完成Exercise情况 Exercise 1 ...

  5. [改善Java代码]线程优先级只使用三个等级

    线程的优先级(priority)决定了线程获得CPU运行的机会,优先级越高获得的运行机会越大,优先级越低获得的机会越小.Java的线程有10个级别(准确的说是11个级别,级别为0的线程是JVM,应用程 ...

  6. 美团点评效果广告实验配置平台的设计与实现

    广告系统中,一个好的实验平台可以令算法.工程.业务的迭代更多.更快.更好.本文详细介绍了美团点评效果广告引擎团队结合自身业务实际,在广告实验配置平台上的实践.目前该平台已经在搜索广告中全面上线,支持线 ...

  7. VRRP浮动路由(浮动路由原理,了解HSRP路由选举原理,实验过程与总结)

    文章目录 前言 单一链路存在的问题 HSRP是思科的私有协议 HSRP (热备份路由选择协议)介绍 VRRP浮动路由原理 Master路由器选举原理 浮动路由原理 实验详解 实验目的 实验过程 主机设 ...

  8. 【实践】美团点评效果广告实验配置平台的设计与实现

    广告系统中,一个好的实验平台可以令算法.工程.业务的迭代更多.更快.更好.本文详细介绍了美团点评效果广告引擎团队结合自身业务实际,在广告实验配置平台上的实践.目前该平台已经在搜索广告中全面上线,支持线 ...

  9. Java基础篇:什么是线程优先级?

    线程优先级被线程调度用来判定何时每个线程允许运行.理论上,优先级高的线程比优先级低的线程获得更多的CPU时间.实际上,线程获得的CPU时间通常由包括优先级在内的多个因素决定. 一个优先级高的线程自然比 ...

最新文章

  1. getparameter java_java中getAttribute与getParameter方法的区别
  2. awk 抓取文件子集
  3. 配置主机路由表(route)(两)
  4. python web-Web开发
  5. 5.fork和vfork
  6. 【转】 MySQL索引类型一览 让MySQL高效运行起来 mysql索引注意事项
  7. wordpress漏洞_用软件工具扫描WordPress / Shopify主题恶意代码以及漏洞分析相关工具...
  8. mongodb python 存文件_Python保存MongoDB上的文件到本地的方法介绍
  9. 实现option上下移动_JS实现Select的option上下移动的方法
  10. 学习第六天@Linq操作
  11. 自动驾驶初创公司Nuro获软银9.4亿美元投资
  12. 优惠劵秒杀优化-分布式锁
  13. 导弹追踪飞机c语言编程,防御导弹 (C语言代码)
  14. 爬虫初学——爬取京东商品的评论(一)
  15. Matlab多项式求值(2)(roots和poly的使用)
  16. 为什么精英都是时间控
  17. 模型剪枝经典论文解读:《Learning Efficient Convolutional Networks through Network Slimming》
  18. Spring中,StringUtils的isEmpty方法已弃用
  19. 具有黑马潜质的电影都有哪些特色?
  20. 透彻理解位图与矢量图的本质区别(小包子觉得讲的很清晰)

热门文章

  1. SSM配置头文件和代码
  2. skin卓沿护肤品怎么样_卓沿这个品牌怎么样 卓沿适合什么年龄
  3. VMware扩大在华研发投入 推动中国研发
  4. 如何预防和检测网页挂马?
  5. Vue实现购物车完整代码
  6. 如何下载和使用Normalize.css?
  7. 五子棋php源码,五子棋 游戏源码(flash+php)
  8. 双边国家地理距离、制度距离和文化距离
  9. PT_大数定律LLN
  10. 大学物理实验不确定度计算器