pintos (4) --Mesa vs. Hoare style

在阅读pintos/src/threads/synch.c的时候,发现了一个令人疑惑的地方:

/* Down or "P" operation on a semaphore. Waits for SEMA's value
to become positive and then atomically decrements it.
This function may sleep, so it must not be called within an
interrupt handler. This function may be called with
interrupts disabled, but if it sleeps then the next scheduled
thread will probably turn interrupts back on. */
void
sema_down (struct semaphore *sema)
{
    enum intr_level old_level;

    ASSERT (sema != NULL);
    ASSERT (!intr_context ());

    old_level = intr_disable ();
    while (sema->value == 0)
    {
        list_push_back (&sema->waiters, &thread_current ()->elem);
        thread_block ();
    }
    sema->value--;
    intr_set_level (old_level);
}
这个函数是信号量的P操作,完成的功能就是
  1. 关中断
  2. 判断信号量是否为0
    • 如果为0,当前进程加入该sema等待队列
    • 不为0,sema–,继续执行
  3. 还原中断

第16行使用了while而不是if,为什么要在这里循环呢?
sema为0陷入阻塞之后,一定是被V操作唤醒的,既然是V操作,那么sema一定不为0,while的意义在哪里呢?


先来看一下V操作:

/* Up or "V" operation on a semaphore.  Increments SEMA's value
   and wakes up one thread of those waiting for SEMA, if any.
   This function may be called from an interrupt handler. */
void
sema_up (struct semaphore *sema) 
{
  enum intr_level old_level;

  ASSERT (sema != NULL);

  old_level = intr_disable ();
  if (!list_empty (&sema->waiters)) 
    thread_unblock (list_entry (list_pop_front (&sema->waiters),
                                struct thread, elem));
  sema->value++;
  intr_set_level (old_level);
}
V操作做了如下的事情
  1. 关中断
  2. 如果waiters队列有进程,执行thread_unblock()
  3. sema++
  4. 还原中断

好像没什么不对的

再来看一下thread_unblock()的实现:
/* Transitions a blocked thread T to the ready-to-run state.
   This is an error if T is not blocked.  (Use thread_yield() to
   make the running thread ready.)
   This function does not preempt the running thread.  This can
   be important: if the caller had disabled interrupts itself,
   it may expect that it can atomically unblock a thread and
   update other data. */
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);
  t->status = THREAD_READY;
  intr_set_level (old_level);
}
thread_unblock()做了如下的事情
  1. 关中断
  2. 将进程添加到ready_list,设置状态为READY
  3. 还原中断

竟然没有进行调度!


OK进入正题:

Mesa vs. Hoare style
  • Hoare style:V操作后立即进行调度。
  • Mesa style:V操作后只将进程unblock,然后继续运行等待系统进行调度。

显然PintOs采用的是Mesa style,所以,被unblock的进程在被调度的时候,sema并不一定可用,比如其他进程又进行了P操作,所以必须再次检查sema,如果不可用则继续block,这就是使用while而不是if的理由。

为什么不立即调度呢?这就是他的优点,不立即调度而是等待系统调度,就减少了调度次数,而每次切换上下文都是繁重的工作,进而降低了系统开销。


相关链接:

http://blog.csdn.net/xiaoguobaf/article/details/52174285
http://blog.chinaunix.net/uid-20545494-id-1929545.html
https://github.com/windr0id/pintos/issues/1

你可能感兴趣的:(pintos)