PintOS lab1 threads 实验记录

Background

首先完成这个实验我们需要理清线程怎么启动的和切换的

下面这张图可以大体表示线程状态的切换

 让我们看看thread init的前世今生吧(:

从start.S汇编调用了一个c函数

 pintos_init初始化了一堆东西,当然里面也包括了thread啦

int
pintos_init (void)
{
  char **argv;

  /* Clear BSS. */  
  bss_init ();

  /* Break command line into arguments and parse options. */
  argv = read_command_line ();
  argv = parse_options (argv);

  /* Initialize ourselves as a thread so we can use locks,
     then enable console locking. */
  thread_init ();
  console_init ();  

  /* Greet user. */
  printf ("Pintos booting with %'"PRIu32" kB RAM...\n",
          init_ram_pages * PGSIZE / 1024);

  /* Initialize memory system. */
  palloc_init (user_page_limit);
  malloc_init ();
  paging_init ();

  /* Segmentation. */
#ifdef USERPROG
  tss_init ();
  gdt_init ();
#endif

  /* Initialize interrupt handlers. */
  intr_init ();
  timer_init ();
  kbd_init ();
  input_init ();
#ifdef USERPROG
  exception_init ();
  syscall_init ();
#endif

  /* Start thread scheduler and enable interrupts. */
  thread_start ();
  serial_init_queue ();
  timer_calibrate ();

#ifdef FILESYS
  /* Initialize file system. */
  ide_init ();
  locate_block_devices ();
  filesys_init (format_filesys);
#endif

  printf ("Boot complete.\n");
  
  if (*argv != NULL) {
    /* Run actions specified on kernel command line. */
    run_actions (argv);
  } else {
    //...
  }
  //...
}

 初始化init线程也叫main线程

 

让我们从最开始开始,我们还要初始化一个init_thread, idel_thread放到ready_list里面,为了即使一个线程也可以做tswith.有点链表哑结点那味。

void
thread_start (void) 
{
  /* Create the idle thread. */
  struct semaphore idle_started;
  sema_init (&idle_started, 0);
  thread_create ("idle", PRI_MIN, idle, &idle_started);

  /* Start preemptive thread scheduling. */
  intr_enable ();

  /* Wait for the idle thread to initialize idle_thread. */
  sema_down (&idle_started);
}

然后就是thread_unblock,thread_block

一般是sleep,或者lock阻塞才用到,把状态变为block

 在ready_list里面选择优先级最高的,然后切换线程上下文

然后就是thread_schedule_tail:Completes a thread switch by activating the new thread's page

  tables, and, if the previous thread is dying, destroying it。还有就是设置一下struct thread*的状态

 thread_unblock就是把线程插入到ready_list里面等待调度。

thread_yield就是出让cpu给别的线程,自己放入ready_list里面

 

thread_exit不言自明

 然后关于时间片这个概念,我们要先从一个硬件中断定时器说起,实际上这个也是单核上能做到并发假象的关键,如果我们关中断的话,就是一个串行程序了,这个debug时可以用的一个trick

注册一个中断函数。

 中断函数来做提高时间,可能这个时间就是本地时钟吧,sleep_tick来唤醒sleep的线程

thread_tick 来做一个时间片耗尽后的出让,也就是thread_yiled()

 大体背景也就是这样,实际上说到这,后面的lab也就是修修补补

分三个部分来讲吧

lab内容

lab1.1 实现 sleep

然后记录下ticks,然后等中断时,遍历减一 


lab1.2 实现优先级调度和优先级捐赠

优先级调度就是ready_list按thread priority做排序,然后每次run_next_thread的时,取优先级最大的

但是在持有锁的情况下,可能发生不符合我们预期的事,这就是优先级翻转,解决办法就是优先级捐赠

 

 还有一个挑战就是优先级捐赠有传递性,多重性(持有多个锁,优先级取最高的)

举个例子

那么我们的实现也就很正常水到渠成了

就是thread里面做一个wait_lockomg因为一个thread只能被一个lock阻塞,然后我们传递优先级也是传递到这个wait_locking,lock->holder可以定位到那个thread,然后递归做就行了。

然后lock_release时,要减低优先级。

让我们看看lock_acquire和lock_release的实现吧

 

 

lab1,3 高级调度

就是实现一个类似BSD4.4 的调度器

有什么优势吗?

 

我们看到recent_cpu和load_avg有一个系数,实际上也就是说更近的recent_cpu和load_avg有着更大的权重。

 

 pintos通过解析参数来选择调度器,如果选择的是mlqfs就是这个调度器,同时也学习了要static(如果不是全局的话,最好加一下,不然可能会重复定义)和external(全局,一个共享,一个是只声明)具体可以看看这篇bloghttps://www.cnblogs.com/honernan/p/13431431.html

然后pintos内核不支持浮点运算,因为Pintos does not support floating-point arithmetic in the kernel, because it would complicate and slow the kernel.

最后也是放大100倍在float里面,然后我们就可以这样观察到小数点后面的东西了,小数点后面两位就不会被转化抹掉。因为我们最终还是int,没有int表示浮点,没有float类型! 

 

 结果

fail了一个点,但是这个中断好像无法避免?因为可能时间刚好卡的比较准,tick+1了,导致这两个点不相等

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值