多处理器架构和Ring 3

吉尔伽美什
void
sema_down (struct semaphore *sema) 
{
  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);
}

上面的代码是PintOS中的一个机械锁定互斥量。PintOS是针对单处理器系统的。因此,仅禁用中断就足够了。另一方将不可能使用互斥体。

因此,让我们考虑一个多处理器设计:

void
sema_down (struct semaphore *sema) 
{
  old_level = intr_disable ();
  while (!lock cmpxchg(1,0)) // it is just pseudocode-idea
    {
      list_push_back (&sema->waiters, &thread_current ()->elem);
      thread_block ();
    }
  intr_set_level (old_level);
}

old_level = intr_disable ();它关闭了中断,但仅在该CPU的上下文中才至关重要。

它可以作为MP体系结构中功能获取互斥量原型但是,出现了问题list_push_back它也必须是安全多线程的。但是,我们不能使用互斥锁来确保它的安全,因为我们现在才实现它!

主要问题是:是否有可能两个(或多个)CPU在Ring 0级别(内核)上执行代码?

并且,取决于第一个答案的子问题:

  1. 如果没有,我上面没有问题。但是,如何实施呢?

  2. 如果是的话(似乎不可能或很难实现),那么我的上述考虑又如何呢(这仅仅是潜在问题的示例)。我们必须使用spinlocks还是lock-free structures

玛格丽特·布鲁姆(Margaret Bloom)

是的,即使在环0,在SMP中,多个CPU仍可以执行相同的代码。

每个CPU都是对称的,因此它可以执行与其他CPU相同的代码路径(包括内核代码),除非该软件实现某种同步。

Linux内核也面临这个问题,并最初实现了一个不太好的解决方案:在进入和退出内核时获取并释放了Big Kernel Lock

这不是一个好的解决方案,因为一次只能有一个CPU可以执行内核代码,但是它实现起来很快,并且与列表中的第一个项目等效。

更好的解决方案是在整个内核中使用更精细的锁。
由于是实现如示例中所示的互斥锁或信号灯之类的睡眠锁的内核,因此它不能依靠这些原语本身1,而必须使用自旋锁或其他更简单的锁形式。

幸运的是,这不是问题,自旋锁(及其变体)在争用较少或关键路径确实很短(例如更新列表)时实际上比互斥锁更好。

您可以查看Linux上的mutex_init,以了解自旋锁用于同步等待任务的队列。

 49 void
 50 __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 51 {
 52         atomic_set(&lock->count, 1);


 53         spin_lock_init(&lock->wait_lock);


 54         INIT_LIST_HEAD(&lock->wait_list);
 55         mutex_clear_owner(lock);
 56 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 57         osq_lock_init(&lock->osq);
 58 #endif
 59 
 60         debug_mutex_init(lock, name, key);
 61 }

因此,第二项的答案是肯定的。


1等待锁时无法入睡。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章