一、实验名称
时钟原语的改进
二、实验目的
1. 理解并掌握Pintos的安装和使用;
2. 初步掌握Pintos内核线程构造及同步机理; 3. 具有对Pintos内核代码进行修改和调试的能力。
三、实验内容及要求
重新实现devices/timer.c中的timer_sleep()函数。该函数现有的实现虽然是正确的,但所采用的是“忙等”技术,通过不停地循环调用thread_yield()并查询是否已经达到等待时间。新的实现要求采用线程同步机制来替换这样的忙等技术。
void timer_sleep (int64_t ticks)的需求说明如下:
将调用此函数的线程挂起至少ticks所指定的若干个时钟周期。当这段时间过去后,将该线程激活并放入就绪队列。此函数可用于实现实时功能,如按照规定的时间间隔发送报文等。
Pintos系统时钟中断频率的缺省值为100,我们不建议修改此值,因为不适当的设置会造成很多意想不到的错误。
要求达到的指标:通过Pintos所提供的所有相关测试。
四、算法设计思想(字体标为红色的为改动的代码)
(一)忙等待VS.唤醒机制的实现:
/* 介绍实现中新声明的或者改变了的主要结构体、全局或局部变量,简短说明其设置的目的?*/
1.在thread.h文件中,我们在 struct thread 结构体中添加一个新的成员变量 ticks_blocked用来记录thread被阻塞了多久: struct thread {
/* Owned by thread.c. */
tid_t tid; /* 线程标识符 */
enum thread_status status; /* 线程状态 */
char name[16]; /* Name (for debugging purposes). */ uint8_t *stack; /* Saved stack pointer. */ int priority; /* 优先级 */
struct list_elem allelem; /* List element for all threads list. */ int ticks_blocked; /* 存储记录该进程已经被block多久了*/ /* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */ #ifdef USERPROG /* Owned by userprog/process.c. */ uint32_t *pagedir; /* Page directory. */
#endif /* Owned by thread.c. */ unsigned magic; /* Detects stack overflow. */ };
2.打开thread.c,并修改thread_create函数,添加变量ticks_blocked,使得ticks_blocked初始化为0。注意添加的位置,需要在线程t创建出来之后,thread_unblock之前
intr_set_level (old_level); /*Initialize added vars*/ t->ticks_blocked = 0;
3.改动timer.c中的timer_sleep函数
Void
timer_sleep (int64_t ticks) /*让此线程等待ticks单位时长,然后再执行。参数是需要等待的时间长度*/
{
/* int64_t start = timer_ticks ();//记录开始时的系统时间 ASSERT (intr_get_level () == INTR_ON);//断言检测,中断应为开 while (timer_elapsed (start) < ticks) //如果流逝时间>=ticks时就返回。否则将持续占用cpu
thread_yield (); */
If(ticks<=0){
Return;// 检查用户程序中的等待时间是否有错; }
enum intr_level old_level=intr_disable(); //保存原先的中断状态 (thread_block函数调用需要中断关闭)!
struct thread * curThread = thread_current();
curThread->ticks_blocked = ticks;//线程应该阻塞(睡眠)的时间间隔
thread_block(); //阻塞进程
intr_set_level (old_level); //恢复原先的中断状态 }
4. thread_block函数的执行:
thread_block (void)
{
ASSERT (!intr_context ()); //检查调的函数符不符合条件,不能从原文中调 ASSERT (intr_get_level () == INTR_OFF); // 检查中断状态必须为关中断
thread_current ()->status = THREAD_BLOCKED; //线程阻塞态 schedule (); //调度程序schedule() }
5.修改timer.c中的timer_interrupt函数,使其每次中断都对所有线程执行block_check函数,用来检测
static void
timer_interrupt (struct intr_frame *args UNUSED)/*UNUSED是一个宏,表示这个参数没用, 每次时间中断时(即每一个时间单位(ticks)) 调用一次这个函数*/
{
ticks++;//计算机系统时钟
enum intr_level old_level=intr_disaable(); //保存原先的中断状态;关中断(稍后可返回中断关闭前的状态)
thread_foreach (checkInvoke,NULL);/*遍历当前TCB链表中所有线程,
对每个线程执行阻塞判断(是否为0),执行checkInvoke函数*/
intr_set_level (old_level); //恢复中断关闭前的状态
thread_tick ();//交给操作系统发出中断并且调度新的线程进驻cpu。 }
6.为thread.c文件中增加上面timer.c中的timer_interrupt函数中用到的函数checkInvoke函数,用来检查每个进程中的block_ticks是否为零 void
checkInvoke(struct thread *t, void *aux UNUSED) {
if (t->status == THREAD_BLOCKED&&t->ticks_blocked>0)/*判断线程是不是阻塞态*/ {
t-> ticks_blocked - -; //将等待的时间自减 if (t-> ticks_blocked = = 0) {
thread_unblock (t); //把t线程重新\"解锁\" } } }
7.在thread.h中对checkInvoke函数添加说明 添加一句:
Void checkInvoke(struct thread* t,void aux UNUSED);
(二)alarm-priority的实现
1.在thread .c中添加比较函数cmp,并在thread.h中添加相关说明 static bool
cmp(const struct list_elem *a,const struct list_elem *b,void *aux){ return (list_entry(a,struct thread,elem)->priority>
list_entry(b,struct thread,elem)->priority);
}
在thread.h中添加相关说明,添加一句:static bool cmp(const struct
list_elem *,const struct list_elem *,void *);
2.将thread.c中thread_unblock的list_push_back(&ready_list,&t->elem);改为:List_insert_ordered(&ready_list,&t->elem,cmp,NULL); void
thread_unblock (struct thread *t) {
enum intr_level old_level;
ASSERT (is_thread (t));
old_level = intr_disable ();
ASSERT (t->status == THREAD_BLOCKED); /*list_push_back (&ready_list, &t->elem);*/
list_insert_ordered (&ready_list, &t->elem,cmp,NULL); t->status = THREAD_READY; intr_set_level (old_level); }
/* Returns the name of the running thread. */
3. 对thread_yield函数和init_thread函数也做类似修改
void
thread_yield (void) {
struct thread *cur = thread_current (); enum intr_level old_level;
ASSERT (!intr_context ());
old_level = intr_disable (); if (cur != idle_thread)
/* list_push_back (&ready_list, &cur->elem);*/
list_insert_ordered (&ready_list, &cur->elem,cmp,NULL); cur->status = THREAD_READY; schedule ();
intr_set_level (old_level);
}
/* Invoke function 'func' on all threads, passing along 'aux'. This function must be called with interrupts off. */
static void
init_thread (struct thread *t, const char *name, int priority) {
ASSERT (t != NULL);
ASSERT (PRI_MIN <= priority && priority <= PRI_MAX); ASSERT (name != NULL);
memset (t, 0, sizeof *t); t->status = THREAD_BLOCKED;
strlcpy (t->name, name, sizeof t->name); t->stack = (uint8_t *) t + PGSIZE; t->priority = priority; t->magic = THREAD_MAGIC;
/* list_push_back (&all_list, &t->allelem);*/
list_insert_ordered (&all_list, &t->allelem,cmp,NULL); }
/* Allocates a SIZE-byte frame at the top of thread T's stack and returns a pointer to the frame's base. */
五、运行结果
。
因篇幅问题不能全部显示,请点此查看更多更全内容