Pintos是Stadford大学为操作系统课程专门开发的一个基于80x86架构的简单操作I型操作系统框架,我们的目标是编写或者改造这一OS。该课题总共分为4个project,如下图所示:
Task one
今天专门来谈第一个project 的第一个问题--Alarm clock的改进。
一.源码分析
Pintos源码/device/timer.c中有一个timer_sleep()函数,如下:
void timer_sleep(int 64_t ticks)
{
int64_t start=timer_ticks();
ASSERT(intr_get_level()==INTR_ON) //此时上下文大状态是开中断
While(timer_elapsed(start)<ticks) //此处为修改设计的部分
Thread_yield();
}
现有问题:
此函数与我们经常使用的sleep()相似,功能是实现让某个线程睡眠一段时间,所谓睡眠一段时间,是指的是让该线程暂时放弃CPU,那么放弃CPU之后线程的状态,就是可以根据自己选择了。一个线程不处于running状态,那么它可以处于ready状态,或者block状态(此时线程当然不能dying)。
若此线程处于ready状态,则该线程处于ready队列中,由时间片轮询法可知,此队列的每一个线程都有一定的机会被CPU再次轮询到,即使此时该想要睡眠的线程没有到达时间,也会再次被CPU轮询到,就出现所谓上面的while形式,当轮询到此线程的时候,首先应该判断该线程是否已经睡眠够了,若不够,则立马放弃CPU的使用,继续进入ready队列中。
二 分析与改进
分析:
由以上分析可以看出,在该线程睡眠期间,每过一段时间,都要被CPU询问一次,让后又立马放弃使用权,如此反复进行,就是在做无用功,要想不做这些无用功,该怎么办呢?改进1:
分析做此无用功的原因,主要是由于改线程在睡眠期间位于ready中,造成它不能好好睡觉,因此我们现在应该做的就是让线程到其他的地方睡觉,即让线程到阻塞队列中睡觉,使其处于block状态。只需在睡眠时间到达时CPU叫醒该线程即可。我们需要在线程结构体中定义一个变量来记录该线程还需要睡眠多少时间,初始应该为睡眠总时间,即int64_t ticks。
源码改进1:
struct thread
{
/* Owned by thread.c. */
tid_t tid; /* Thread identifier. */
enum thread_status status; /* Thread state. */
char name[16]; /* Name (for debugging purposes). */
uint8_t *stack; /* Saved stack pointer. */
int priority; /* Priority. */
struct list_elem allelem; /* List element for all threads list. */
/* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */
int block_ticks; /* 线程阻塞时间*/
};
void timer_sleep(int 64_t ticks)
{
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
/*while (timer_elapsed (start) < ticks)
thread_yield ();*/
struct thread *t;
t=thread_current (); //获取当前线程
t->block_ticks = ticks; //初始化,记录阻塞时间
enum intr_level old_level; //定义变量保存原先的中断状态
old_level = intr_disable (); //关闭中断
thread_block(); //阻塞线程
intr_set_level (old_level); //恢复中断
}
改进2:
每一次一个时钟周期时,此剩余睡眠时间block_ticks就应该减一次,当其减为0时,表示睡眠时间够了,就要唤醒该线程。因此需要每次时钟中断时,在做完block_ticks--,操作时都应该判断一下刚才我们阻塞的线程是否已经有到达睡眠时间。在pintos源码中,thread_block()函数把阻塞的线程均放入all_list队列中,借助thread_foreach()函数,我们每次可以遍历all_list队列中的线程,判断是否需要unblock操作。在thread_foreach()中,我们需要加入一个判断是否解除阻塞函数,即block_check()函数。
源码改进2:
void block_check(struct thread *t, void *aux UNUSED)
{
if (t->status == THREAD_BLOCKED && t->block_ticks>0)
{
t->block_ticks--;
if (t->block_ticks == 0) //若到达睡眠时间
{
Thread_unblock (t); //解阻塞
}
}
}
timer_interrupt (struct intr_frame *args UNUSED)
{
ticks++; //此处为全局变量ticks,注意区别上述的局部变量
enum intr_level old_level; //记录原来的中断状态
old_level=intr_disable(); //thread_foreach函数要求关中断
thread_foreach (block_check, 0); //遍历all_list队列中的线程,是否有解阻塞的线程
intr_set_level (old_level); //恢复中断
thread_tick ();
}
以上就是我对第一部分的小结,如有理解有误的地方,欢迎看到博客的各位指正

7299

被折叠的 条评论
为什么被折叠?



