【问题标题】:A multiprocessor architecture and Ring 3多处理器架构和 Ring 3
【发布时间】:2016-09-20 10:32:27
【问题描述】:
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. 如果是(这似乎不可能或很难实现),我的上述考虑呢(这只是潜在问题的示例)。 我们必须使用spinlockslock-free structures 吗?

【问题讨论】:

  • 你能把帖子简化为一个明确的问题吗?如果自旋锁和无锁编程用于同步对非常短的关键部分(例如更新列表的关键部分)的访问并且无法避免 AFAIK,那么它们也不错。
  • @MargaretBloom,我进行了编辑以更清楚地说明我的要求。基本上,它是单一问题的帖子。我没有摆脱我的子问题,因为它们依赖于上下文,没有必要将它们放在其他帖子中。 ( 我认同)。希望对你更友好。
  • 我对此特别困惑:“两个(或更多)CPU 是否有可能在 Ring 3 级别(内核)上执行代码”。为什么你会惊讶于不同的 CPU 可以执行相同的代码?以及为什么在Ring 3(即用户模式)旁边有一个kernel
  • @MargaretBloom,CPU 可以执行相同的代码并不奇怪。很明显——他们可以。我考虑他们是否可以同时在 Ring 0(我编辑了我的帖子,我之前犯了一个错误)级别上​​执行代码。
  • 由于 IOAPIC 可以跨多个内核分配外部中断,这将要求每个处理器能够同时操作环 0 中的代码。处理器上的 ring 3 程序可能会请求进行系统调用,从而可能将运行它的处理器切换到 ring 0。这可以在所有内核上完成。所以是的,有可能同时在多个内核上的 ring 0 处运行代码。如果您有一个仅使用单核的多核系统(启动时默认),则没有问题。您必须在使用之前启用/引导每个核心。

标签: multithreading x86 operating-system


【解决方案1】:

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

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

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

这不是一个好的解决方案,因为一次只有一个 CPU 可以执行内核代码,但它实现起来很快,并且相当于您列出的第一项。

更好的解决方案是在整个内核中使用更精细的锁。
由于是内核实现了示例中显示的互斥锁或信号量等休眠锁,因此它不能依赖这些原语本身1,必须使用自旋锁或其他更简单的锁定形式。

幸运的是,这不是问题,当争用较少或关键路径非常短(如更新列表)时,自旋锁(和 its variants)实际上比互斥锁更好。

您可以从 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你不能一边等待一边睡觉一边等待锁。

【讨论】:

    猜你喜欢
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 2014-06-21
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多