OS-2019Pintos第一次实验


小组成员:
                黄   东:16281255
                苏荣天:16281141
                罗泽昊:16281294
                李    超:16281194
                袁恩泽:16281307

1 Alarm Clock

1.1 源码分析

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 实现思路

        这一部分要求我们重新实现定义在device/timer.c中的timer_sleep函数,通过刚刚对源码的分析我们可以发现,现有的timer_sleep函数是一种称为“忙等待”的实现方式,也就是说,当我们调用timer_sleep函数时,它会在循环中检查当前时间是否已经过去了ticks个时钟,如果没有,将会调用thread_yield函数,将当前进程加入到就绪队列,将CPU让给就绪队列中的其他进程。由于在这个过程中,进程在CPU就绪队列和运行队列间来回切换,而且即使没有到达ticks个始终,CPU依然会激活进程,因此,浪费了大量的CPU资源以及时间。
        为了避免这个问题,我们可以将当进程在调用timer_sleep函数时,直接将其阻塞,同时在结构体加入一个变量,用来记录当前进程距执行还差多少时刻。当时间到0时,便将进程加入到就绪队列中。

1.3 实现代码

为实现我们的想法,首先我们需要在线程结构体中加入一个变量,ticks_blocked,用于记录进程距离执行还差的时间

int64_t ticks_blocked;

然后我们需要修改thread_create函数,使得在进程被创建时初始化ticks_blocked为0

t->ticks_blocked = 0;

现在,我们需要修改timer_interrupt函数,使得每过一个ticks,ticks_blocked就能够相应的减1.为实现这一功能,我们需要在thread.c中新建一个函数blocked_thread_check,当ticks_blocked到0时,调用thread_unblock,将进程加入到就绪队列。

void blocked_thread_check (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);
      }
  }
}

那么我们如何对阻塞队列中的每一个进程都调用这个函数呢,这时我们就需要用到thread_foreach函数,而他的功能,就是对所有的线程执行参数中的thread_action_func

/* Invoke function 'func' on all threads, passing along 'aux'.
   This function must be called with interrupts off. */
void thread_foreach (thread_action_func *func, void *aux)
{
   
  struct list_elem *e;

  ASSERT (intr_get_level () == INTR_OFF);

  for (e = list_begin (&all_list); e != list_end (&all_list);
       e = list_next (e))
    {
   
      struct thread *t = list_entry (e, struct thread, allelem);
      func (t, aux);
    }
}

最后,我们重新实现timer_sleep函数

void timer_sleep (int64_t ticks)
{
   
  if (ticks <= 0)
  {
   
    return;
  }
  ASSERT (intr_get_level () == INTR_ON);
  enum intr_level old_level = intr_disable ();
  struct thread *current_thread = thread_current ();
  current_thread->ticks_blocked = ticks;
  thread_block ();
  intr_set_level (old_level);
}

1.4 实验结果

在这里插入图片描述

2 Priority Scheduling

首先,我们来分析一下源码,可以看到,在线程的结构体中已经为我们定义好了priority,进一分析发现,priority的取值范围是0-63,而且数值越小,优先级越低。
在这里插入图片描述
在这里插入图片描述
为了实现进程能按优先级执行,我们主要需要实现三点,分别是:一,就绪队列中的进程能够按照优先级排序,二,当高优先级进程进入就绪队列时,低优先级进程立即放弃CPU,同时交给高优先级进程执行。三,当进程同时在等待锁时,应首先唤醒高优先级的进程。线程可以随时提高或降低自己的优先级。

2.1就绪队列为优先级队列

为了保证就绪队列为一个优先级队列,我们就需要使得进程每一次加入队列时,都是按照优先级排序。那么现在我们需要考虑的就是进程在什么情况下会被加入就绪队列,通过之前的分析可以发现,当进程调用thread_unblock(),init_thread(),thread_yield()这三个函数时,进程将会被加入就绪队列,进一步阅读这三个函数可以发现,他们调用的都是list_push_back(),也就是说我们修改这个函数就可以实现我们想要的功能。这时我们发现了list_insert_ordered()函数,从命名上我们就可以看出他的功能。

/* Inserts ELEM in the proper position in LIST, which must be
   sorted according to LESS given auxiliary data AUX.
   Runs in O(n) average case in the number of elements in LIST. */
void
list_insert_ordered (struct list *list, struct list_elem *elem,
                     list_less_func *less, void *aux)
{
   
  struct list_elem *e;

  ASSERT (list != NULL);
  ASSERT (elem != NULL);
  ASSERT (less != NULL);

  for (e = list_begin (list); e != list_end (list); e = list_next (e))
    if (less (elem, e, aux))
      break;
  return list_insert (e, elem);
}

于是,我们将这三个函数里的list_push_back()全部修改为list_insert_ordered()

list_insert_ordered (&ready_list, &t->elem, (list_less_func *) &thread_cmp_priority, NULL);//     thread_unblock()
list_insert_ordered (&all_list, &t->allelem
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值