Nachos实验1实现线程id、限制线程数和更改调度算法(按优先级调度)
一、理解Nachos线程的运行及调度原理
Nachos实验主要是为了使我们深入的理解操作系统结构,Nachos也是一个操作系统,但是它很简便,我们可以很容易的对它进行改动;通过对Nachos的实验来增加我们对操作系统的理解,当前这个实验主要是通过我们实现Nachos线程id和优先级调度来对操作系统进程和线程的理解。Nachos里面主要分为内核线程(例如main线程)和用户线程,主要通过主线程来操作,例如新建和调度线程。其实对于增加线程id和限制最大线程数,只要了解进程的实现原理,看代码也会非常的容易理解,这样就会非常简单了。
对于理解这次实验代码,我认为,需要看thread.h、thread.cc、scheduler.h、scheduler.cc、List.h、List.cc、main.h、main.cc,对于main.h和main.cc,只需要知道在运行Nachos的时候加-K命令(“./nachos -K”)就会进入线程测试就行了。
二、增加线程ID和最大线程数
在增加实现线程id和最大线程数时,thread类的构造函数尽量不要改动,只需再重构一个构造方法,因为之前的构造函数可能在Nachos的其他类里会调用它,所以我们不能再之前的构造函数里构造,这样才不会打乱原系统的正确性,所以需要增加一个构造函数Thread(char* debugName,int priority);至于int priority先不用管,这是之后优先级调度需要用到的参数,不影响我们使用这个构造函数
1.增改class thread,增加线程id成员和一些需要用到的成员方法
#define MAX_SIZE 128//最大线程数
//pk数组主要记录线程号被使用的状态
//下标位线程号,数组对应值位线程号状态
//对应值为0时,表示该线程号没有线程占用
//对应值为1时,表示该线程号被占用
static int pk[MAX_SIZE]={
0};
static int threadMAX = 0;//记录线程数
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 pointer
void *machineState[MachineStateSize]; // all registers except for stackTop
int tid;
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
Thread(char* debugName,int priority);//新构造函数
int getTid(){
return this->tid;};//获得线程id
void Fork(VoidFunctionPtr func, void *arg); //将线程加入就绪队列
// Make thread run (*func)(arg)
void Yield(); //打断当前线程,运行就绪队列里的线程
// Relinquish the CPU if any
// other thread is runnable
void Sleep(bool finishing);//将当前线程阻塞
// Put the thread to sleep and
// relinquish the processor
void Begin(); // Startup code for the thread
void Finish(); //线程运行结束
// The thread is done executing
void CheckOverflow(); // Check if thread stack has overflowed
void setStatus(ThreadStatus st) {
status = st; }//设置线程状态
char* getName() {
return (name); }//获取线程名字
void Print() {
cout << name; }//打印线程名字
void SelfTest(); //测试方法 // test whether thread impl is working
private:
// some of the private data for this class is listed above
int *stack; // Bottom of the stack
// NULL if this is the main thread
// (If NULL, don't deallocate stack)
ThreadStatus status; // ready, running or blocked
char* name;
void StackAllocate(VoidFunctionPtr func, void *arg);
// Allocate a stack for thread.
// Used internally by Fork()
// A thread running a user program actually has *two* sets of CPU registers --
// one for its state while executing user code, one for its state
// while executing kernel code.
int userRegisters[NumTotalRegs]; // user-level CPU register state
public:
void SaveUserState(); // save user-level register state
void RestoreUserState(); // restore user-level register state
AddrSpace *space; // User code this thread is running.
};
2.在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;
}
Thread::Thread(char* threadName,int priority)//新构造函数
{
if(++threadMAX > MAX_SIZE){
//限制线程数
cout<<"最大线程数:"<<MAX_SIZE<<"!!!"<<endl;
ASSERT(threadMAX<=MAX_SIZE);
}
int j;
for(j=0;j<MAX_SIZE;j++){
//设置id
if(pk[j]==0){
this->tid = j+1;
pk[j] = 1;
break;
}
}
name = threadName;
stackTop = NULL;
stack = NULL;
status = JUST_CREATED;
for (int