操作系统:Pintos Project 1

这篇博客介绍了Pintos操作系统Project1的完成过程,涉及主要内容包括重新实现timer_sleep()以实现非忙等待,以及在alarm测试集中涉及的线程睡眠状态管理和调度。此外,还详细讲述了如何实现线程优先级捐赠,以满足priority测试集的要求。文章通过修改lock_acquire(), lock_release()等函数,确保在lock操作中进行优先级捐赠,并在多级队列反馈调度(mlfqs)测试集中进行相应的调整。" 121394662,11615661,广东开放大学基础写作考核试题解析,"['教育', '考试', '写作技巧', '大学课程', '在线学习']
摘要由CSDN通过智能技术生成

也是借鉴了网上一些实现,勉勉强强将Project1过了,不过感觉代码中还是有些问题的。

alarm测试集

这个测试集要求重新实现timer_sleep()函数,将原来的忙等待改为非忙等待。
思路跟阻塞线程类似:

  • 1.为线程增加一个新的状态,表示线程正处在sleep中。
    thread.h:在文件靠前添加宏定义:
#define THREAD_SLEEP THREAD_BLOCKED
  • 2.在内核中增加一个列表sleep_list,用于存放处于THREAD_SLEEP状态的线程。
    thread.c:在文件靠前添加静态变量:
static struct list sleep_list;
  • 3.在struct thread结构体中添加两个成员变量,用于保存与THREAD_SLEEP状态相关的信息。
    thread.h:修改后的struct thread结构体:
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. */

    struct list_elem slpelem;//sleep_list的链表元素
    int64_t sleep_ticks;//还需要等待的ticks次数

#ifdef USERPROG
    /* Owned by userprog/process.c. */
    uint32_t *pagedir;                  /* Page directory. */
#endif

    /* Owned by thread.c. */
    unsigned magic;                     /* Detects stack overflow. */
  };
  • 4.为了实现非忙等待的timer_sleep(),需要实现几个函数,具体功能下文会解释。
    thread.h:在文件靠后添加函数声明:
void thread_sleep(int64_t ticks);
void thread_foreach_sleep (void);
bool thread_less_priority(const struct list_elem *a,const struct list_elem *b,void *aux UNUSED);
  • 5.实现thread_sleep()函数,该函数会将当前线程放入sleep_list队列中,并更新线程信息,最后调用schedule()进行新线程调度。该函数会在timer_sleep()中被调用。
    thread.c:在文件靠后添加以下代码:
void
thread_sleep(int64_t ticks)
{
  enum intr_level old_level=intr_disable();

  struct thread *t=thread_current();//获取当前线程
  t->sleep_ticks=ticks;//设置当前线程需要等待的ticks次数
  list_push_back (&sleep_list, &t->slpelem);//将当前线程放入sleep_list队列中
  t->status = THREAD_SLEEP;//更新当前线程的状态为THREAD_SLEEP
  schedule ();//进行线程调度,交出cpu,让其他线程继续执行

  intr_set_level(old_level);
}
  • 6.实现thread_foreach_sleep()函数,该函数会遍历sleep_list队列,并将其中的每个线程的sleep_ticks减1;若某个线程的sleep_ticks为0,即该线程不需要再继续等待,便将该线程从sleep_list队列移至就绪队列中。该函数会在timer_interrupt()中被调用。
    thread.c:在文件靠后添加以下代码:
void
thread_foreach_sleep (void)
{
  enum intr_level old_level=intr_disable();

  struct list_elem *e;

  for (e = list_begin (&sleep_list); e != list_end (&sleep_list);
       e = list_next (e))//遍历sleep_list中的每一个元素
    {
      struct thread *t = list_entry (e, struct thread, slpelem);//得到线程结构体
      t->sleep_ticks--;//更新sleep_ticks
      if(t->sleep_ticks==0)//如果还需等待的ticks为0,即sleep时间到了
      {
        list_remove(e);//将该线程从sleep_list队列中删除
        t->status = THREAD_READY;//将该线程的状态设置为THREAD_READY
        list_push_back (&ready_list, &t->elem);//将该线程放入就绪队列中
      }
    }

  intr_set_level(old_level);
}
  • 7.实现thread_less_priority()函数,该函数会比较传入线程a和b的优先级,若a的优先级小于b的,则返回真,否则返回假。该函数会在next_thread_to_run中被调用,用来从就绪队列中选择优先级最高的线程。
    thread.c:在文件靠后添加一下代码:
bool
thread_less_priority(const struct list_elem *a,const struct list_elem *b,void *aux UNUSED)
{
  return list_entry(a,struct thread,elem)->priority<list_entry(b,struct thread,elem)->priority;
}
  • 8.修改timer_sleep()函数:一是要对输入参数进行合法性检查,输入参数ticks必须大于0才有意义;二是要将其改为非忙等待,看了上面的内容,其实思路已经很清楚了,只要调用thread_sleep()将当前线程扔到sleep_list队列中就行了。
    timer.c:修改后的timer_sleep()函数:
void
timer_sleep (int64_t ticks) 
{
  if(ticks<=0)
    return;

  thread_sleep(ticks);
}
  • 9.修改timer_interrupt()函数:当每个ticks中断到来时,需要对sleep_list中的线程进行更新,否则sleep中的线程将永远不会被唤醒。
    timer.c:修改后的timer_interrupt()函数:
static void
timer_interrupt (struct intr_frame *args UNUSED)
{
  ticks++;
  thread_foreach_sleep();//增加对sleep_list中线程的更新
  thread_tick ();
}
  • 10.需要对新加入的sleep_list在系统启动后进行初始化,所以在thread_init函数中添加一行代码。
    thread.c:修改后的thread_init()函数:
void
thread_init (void) 
{
  ASSERT (intr_get_level () == INTR_OFF);

  lock_init (&tid_lock);
  list_init (&ready_list);
  list_init (&all_list);
  list_init (&sleep_list);//对sleep_list进行初始化

  /* Set up a thread structure for the running thread. */
  initial_thread = running_thread ();
  init_thread (initial_thread, "main", PRI_DEFAULT);
  initial_thread->status = THREAD_RUNNING;
  initial_thread->tid = allocate_tid ();
}
  • 11.收尾工作,因为project要求在调度下一个进程时,选择优先级最高的来执行,所以需要修改next_thread_to_run()函数。该函数原先选择就绪队列中的第一个线程来执行,现在我们利用库函数中提供的list_max()来选择其中优先级最高的线程。
    thread.c:修改后的next_thread_to_run()函数:
static struct thread *
next_thread_to_run (void) 
{
  struct list_elem *e;
  if (list_empty (&ready_list))
    return idle_thread;
  else
  {
    e=list_max (&ready_list,&thread_less_priority,NULL);//从前往后找到第一个优先级最高的线程
    list_remove(e);//从就绪队列中将选中的线程删去
    return list_entry (e, struct thread, elem);
  }
}

priority测试集

这个测试集主要是要求实现锁的优先级捐赠,及将cond改为按优先级选择下一线程,并且保证执行中的线程始终是优先级最高的。
因为原先的实现中是将lock视为值为1的信号量来处理的,为了实现优先级捐赠,需要用到其中的等待队列,但这样包裹一层结构体觉得很麻烦,所以对lock做了较大改动。

  • 1.为了实现优先级捐赠,我们先考虑struct thread需要增加哪些变量。我们需要记录当前线程的基础优先级,这样当捐赠结束时才能恢复原先的优先级;我们需要记录线程已经持有的锁,这样才能在需要的时候(获得或释放一个锁时),根据这些锁来决定新的捐赠的优先级大小;还需要记录线程正在等待的锁,这样当发生嵌套捐赠时,可以根据这个变量不断向前找到下一个被捐赠对象。
    thread.h:修改后的struct thread结构体:
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;           
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值