【nachos】山东大学操作系统课设实验nachos系统(1):线程初探

实验内容:
下载并编译nachos之后(注意只能在32位linux下成功编译)
1. 跟踪执行nachos之后,观察以下函数的执行
(a) 上下文切换函数 SWITCH()
(b) 函数 ThreadRoot()

  1. 使用gdb运行nachos,回答一下问题:
    (a) 在你的nachos中,以下函数的地址是什么:
    1
    i. InterruptEnable()
    ii. SimpleThread()
    iii. ThreadFinish()
    iv. ThreadRoot()
    并描述你怎样找到他们的地址的.
    (b) 以下线程对象的地址是什么?
    i. main thread
    ii. 被主线程创造的forked thread
    并描述怎么找到他们的
    (c) 主线程第一次执行到SWITCH函数的时候,它执行到最后一条语句ret后,返回给cpu的地址是什么?这个地址在程序中指向什么?
    (d) 子线程第一次执行到SWITCH函数的时候,它执行到最后一条语句ret后,返回给cpu的地址是什么?这个地址在程序中指向什么?

实验步骤与内容:
1、在threads目录下使用make命令编译
2、用gdb nachos命令开启调试
3、查看源代码的执行,熟悉执行流程
4、程序自main函数开始执行,在Initialize函数中,初始化了main线程的 对象。继续执行执行ThreadTest函数后打印出内容
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第1张图片
可见本程序运行关键步骤在于ThreadTest函数。
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第2张图片
进入ThreadTest函数后可以发现,函数中完成了
①创建新的线程对象forked thread,
②调用对象的Fork方法,绑定SimpleThread这个函数,
③主进程执行函数SimpleThread。
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第3张图片
在SimpleThread函数中做的工作很简单,只是打印出线程n的循环次数i,然后使线程yield。

接下来分析Yield函数和Fork函数。
Fork函数:
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第4张图片
可以看出,函数完成的工作是
①为线程分配栈空间,在StackAllocate函数中主要进行以下数据的初始化
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第5张图片
可以看出它为线程定义了整个生命周期各个阶段的入口地址和参数,包括线程初始化函数ThreadRoot,fork函数中传入的函数指针,线程结束函数ThreadFinish。
②将线程本身添加到scheduler的就绪队列中等待调度。本步操作是原子操作不允许被中断。

Yield函数:
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第6张图片
操作:①将当前线程添加到就绪队列
②scheduler切换至下一个可以运行的线程。
综上,两步操作中途不允许打断,且完成的工作是打断当前线程,允许就绪队列中下一个线程被调度运行,自身加入就绪队列。

了解了以上两个函数,可以看出,子线程被fork了之后,simpleThread函数将会在其生命周期中得以执行,且子线程加入就绪队列,但此时并未得到执行的机会。而主线程执行SimpleThread函数,打出一句话后,调用yield后会将执行权交给子线程,子线程重复该过程,打印之后将执行权交换,直到执行完毕。以上过程再simpleThread中重复数次之后,子线程在simpleThread执行完毕后进入ThreadFinish的阶段被回收,主线程因为还有其他操作所以继续执行。

观察SWITCH和ThreadRoot的执行:
SWITCH和ThreadRoot本身是汇编代码,需要进入swith.s文件查看
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第7张图片
观察易知:switch函数完成的操作很简单:将当前正在执行的状态存入“旧线程”对象中,从“新线程”对象中取出运行状态加载到寄存器,并跳转到ra即将要执行的代码地址。

ThreadRoot:
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第8张图片
ThreadRoot是线程整个生命周期的一个整合,会跳转到不同的函数入口以完成线程的整个生命周期。
5、在题目2(b)中的函数上设置断点,记录其地址即为答案
【nachos】山东大学操作系统课设实验nachos系统(1):线程初探_第9张图片
6、删除上述断点,在SWITCH和ThreadRoot和Initialize和ThreadTest上设置断点
7、执行程序,程序进入Initailize,执行149行currentThread = new Thread(“main”);使用print currentThread即可查看主线程对象地址
8、继续执行程序,进入ThreadTest函数,执行46行Thread *t = new Thread(“forked thread”);使用print t查看子线程对象地址
9、继续执行,进入SWITCH函数,SWITCH和ThreadRoot是汇编代码,SWITCH负责切换当前两个进程的上下文,ThreadRoot是整个进程的生命周期。单步ni执行至SWITCH切换到ThreadRoot时,是主进程切换至了子进程,子进程刚刚进入生命周期。此时ThreadRoot第一句的地址是SWITCH的ret,代表跳转到以下地址执行。
10、再次执行,执行到SWITCH,因为两个进程交换执行,所以这次是子进程交换至主进程。同上步,即为2(c),2(d)两题的解。

你可能感兴趣的:(nachos)