Shy*_*yam 15 c multithreading synchronization mutex linux-kernel
我理解等待条件变量的线程原子地释放锁并进入睡眠状态,直到被另一个线程的条件信号唤醒(当满足特定条件时).在它醒来之后,它以原子方式重新获得锁定(不知何故神奇地)并根据需要进行更新并解锁关键部分.
如果有人能解释如何在内核和硬件/汇编级别实现这个conditional_wait()过程,那会很棒吗?
锁如何以原子方式释放并重新获得?内核如何确保它?
这里的睡眠究竟意味着什么?这是否意味着上下文切换到另一个进程/线程?
在线程休眠期间,如何通过在内核级别实现的信号唤醒此线程,以及是否为这些机制提供了任何硬件特定支持?
编辑:
似乎"futex"是管理这种等待/信号的人.缩小我的问题:futex系统如何调用等待和通知条件变量是如何实现/在低级别工作?
Ser*_*eyA 14
从高层次(因为你问这个问题,你需要高水平)它并不复杂.首先,您需要了解责任层面.基本上有3层:
通常,这些职责并不重叠 - 内核不能只做硬件可以做的事情,硬件不能做只有内核才能做的事情.考虑到这一点,记住在锁定方面很少有硬件知道它是有用的.它几乎归结为
这几乎是所有CPU都可以做到的.如您所见,此处没有futex,互斥或条件变量.这个东西是由具有CPU支持的操作的内核完成的.
让我们看一下内核如何实现futex调用的非常高的层次.实际上,futex有点复杂,因为它根据需要混合了用户级调用和内核级调用.让我们看看'纯'互斥体,仅在内核空间中实现.在较高的层面上,它将是足够的示范.
最初创建互斥锁时,内核会将内存区域与其关联.该区域将保持锁定或解锁的互斥锁值.之后,内核被要求锁定互斥锁,它首先指示CPU发出内存屏障.互斥锁必须充当屏障,以便在获取(或释放)互斥锁之后读取/写入的所有内容对其余CPU都是可见的.然后,如果它被设置为0,它使用CPU支持的比较和设置指令将内存区域值设置为1.(有更复杂的可重入互斥锁,但不要让它们与它们复杂化).CPU保证,即使多于一个线程同时尝试执行此操作,也只有一个会成功.如果操作成功,我们现在'持有互斥锁'.一旦要求内核释放互斥锁,内存区域设置为0(不需要有条件地执行此操作,因为我们知道我们持有互斥锁!)并发出另一个内存屏障.内核还会更新其表中的互斥锁状态 - 请参阅下文.
如果互斥锁定失败,内核会将线程添加到其表中,该表列出了等待特定互斥锁释放的线程.当互斥锁被释放时,内核会检查正在等待这个互斥锁的线程,以及"调度"(即准备执行)其中一个(如果有多个,哪个将被调度或唤醒取决于多种因素,在最简单的情况下,它只是随机的).调度的线程开始执行,再次锁定互斥锁(此时它可能再次失败!)并且生命周期继续.
希望它确实至少有一半意义:)