gpt4 book ai didi

c - conditional_wait() 如何在内核和硬件/汇编级别实现?

转载 作者:太空狗 更新时间:2023-10-29 16:34:09 24 4
gpt4 key购买 nike

我知道等待条件变量的线程会自动释放锁并进入休眠状态,直到被来自另一个线程的条件信号唤醒(当满足特定条件时)。唤醒后,它会自动重新获取锁(以某种方式神奇地)并根据需要进行更新并解锁关键部分。

如果有人可以解释这个 conditional_wait() 过程是如何在内核和硬件/汇编级别实现的,那就太好了?

如何以原子方式释放和重新获取锁?内核如何确保它?

睡在这里到底是什么意思?这是否意味着上下文切换到另一个进程/线程?

在线程休眠期间,这个线程通过信号唤醒是如何在内核级别实现的,是否为这些机制提供了任何特定于硬件的支持?

编辑:

似乎“futex”就是管理这个等待/信号的人。缩小我的问题范围:用于等待和通知条件变量的 futex 系统调用是如何在底层实现/工作的?

最佳答案

在高层次上(既然你在问这个问题,那么高层次就是你所需要的)它并不那么复杂。首先,您需要了解责任的层次。基本上有 3 层:

  • 硬件级别——通常是可以在单个 ASM 指令中编码的东西
  • 内核级别 - 操作系统内核所做的事情
  • 应用层——应用做的事情

通常,这些职责不会重叠 - 内核不能做只有硬件可以做的事情,硬件不能做只有内核可以做的事情。考虑到这一点,记住当谈到锁定时,很少有硬件知道它是很有用的。它几乎可以归结为

  • 原子算术 - 硬件可以锁定特定的内存区域(确保没有其他线程访问它),对其执行算术运算并解锁该区域。这只能适用于芯片本身支持的算法(没有平方根!)和硬件本身支持的大小
  • 内存屏障或栅栏——也就是说,在指令流中引入屏障,这样当 CPU 重新排序指令或使用内存缓存时,它们就不会越过这些栅栏并且缓存会是新鲜的
  • 条件设置(比较并设置)- 如果内存区域为 B,则将内存区域设置为值 A,并报告此操作的状态(是否已设置)

这几乎是 CPU 可以做的所有事情。如您所见,这里没有 futex、mutex 或条件变量。这些东西是由具有 CPU 支持的操作的内核生成的。

让我们从一个非常高的层次来看内核如何实现 futex 调用。实际上,futex稍微复杂一些,因为它是用户级调用和内核级调用按需混合的。让我们研究一下仅在内核空间中实现的“纯”互斥锁。在高层次上,这将是足够的示范。

当最初创建互斥体时,内核将一个内存区域与其相关联。该区域将保存被锁定或解锁的互斥量值。稍后,内核被要求锁定互斥量,它首先指示 CPU 发出内存屏障。互斥锁必须充当屏障,以便在获取(或释放)互斥锁后读取/写入的所有内容对其余 CPU 可见。然后,它使用 CPU 支持的比较和设置指令将内存区域值设置为 1,如果它被设置为 0。(有更复杂的可重入互斥锁,但我们不要用它们使图片复杂化)。 CPU 保证即使有多个线程同时尝试执行此操作,也只有一个会成功。如果操作成功,我们现在“持有互斥量”。一旦要求内核释放互斥锁,内存区域将设置为 0(不需要有条件地这样做,因为我们知道我们持有互斥锁!)并发出另一个内存屏障。内核还会更新其表中的互斥锁状态 - 见下文。

如果互斥锁定失败,内核会将线程添加到它的表中,该表列出了等待释放特定互斥的线程。当互斥体被释放时,内核检查哪些线程正在等待这个互斥体,并"dispatch"(即准备执行)其中之一(如果有多个线程,将调度或唤醒哪个线程取决于许多因素,在最简单的情况下,它只是随机的)。被调度的线程开始执行,再次锁定互斥量(此时它可能再次失败!),生命周期继续。

希望它至少有一半的意义:)

关于c - conditional_wait() 如何在内核和硬件/汇编级别实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33431953/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com