linux - epoll()、互斥量和信号量之类的系统调用是如何在后台实现的?

标签 linux multithreading asynchronous linux-kernel operating-system

这真是一个困惑我很久的问题。我尝试了很多谷歌搜索,但仍然不太明白。我的问题是这样的:

对于epoll()、mutex、semaphore等系统调用,它们有一个共同点:一旦有事情发生(以mutex为例,线程释放锁),就会有一个线程被唤醒(线程等待锁的人可以被唤醒)。

我想知道这种机制(一个线程中的事件发生,然后另一个线程被通知)是如何在幕后实现的?我只能想出两种方法:

  1. 硬件级别的中断:比如另一个线程一释放锁,就会发生边沿触发。
  2. Busy waiting:在很低的级别忙着等待。例如,一旦另一个线程释放锁,它就会从 0 变为 1,以便等待锁的线程可以检查该位。

我不确定我的猜测(如果有的话)中的哪一个是正确的。我想阅读 linux 源代码在这里会有帮助。但是对于我这种菜鸟来说有点难。在这里有一个大概的想法加上一些伪代码会很棒。

最佳答案

Linux 内核有一个名为“等待队列”的内置对象类(其他操作系统也有类似的机制)。等待队列是为所有类型的“可等待”资源创建的,因此内核中有相当多的等待队列。当线程检测到它必须等待一个资源时,它就加入相关的等待队列。大致过程如下:

  1. 线程将其控制结构添加到与所需等待队列关联的链表中。
  2. 线程调用调度程序,它将调用线程标记为休眠,将其从“准备运行”列表中删除并将其上下文隐藏在 CPU 之外。然后,调度程序可以自由选择任何其他线程上下文来加载到 CPU 上。

当资源可用时,另一个线程(无论是用户/内核线程还是由中断处理程序调度的任务——那些通常搭载在特殊的“工作队列”线程上)调用相关的“唤醒”调用等待队列。 “唤醒”是指调度器应从等待队列链表中删除一个或多个线程控制结构,并将所有这些线程添加到“准备运行”列表中,这将使它们能够在适当的时候被调度。

这里有更多的技术概述: http://www.makelinux.net/ldd3/chp-6-sect-2

关于linux - epoll()、互斥量和信号量之类的系统调用是如何在后台实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41155494/

相关文章:

c# - 为什么 Task.WhenAll(taskList) 不起作用?

c - 执行 bash 命令并在 C 中获取输出

java - Java 中的 StampedLock 是什么?

ruby-on-rails - 可以在 Thread::handle_interrupt block 之外异步处理 ruby​​ 异常吗?

android - Pjsip 在多线程中调用它的函数时在 android 上崩溃

java - 高效等待资源

linux - 编写具有自定义选项和行为的 sed 脚本

linux - 使用 Linux/Bash 对空格分隔的数字进行排序

linux - Intel-64 和 ia32 原子操作获取-释放语义和 GCC 5+

c# - 暂停/恢复异步任务的模式?