请问编程语言中阻塞机制在操作系统最底层是如何实现的?

2019-12-26 10:24:51 +08:00
 squancher

首先大致问题如上,有以下两个疑问

  1. 有一种说法是程序阻塞不占用 CPU 资源。根据我所查阅到的资料,JAVA 为例,阻塞机制最后都到了 native 方法,也就是 C 语言实现,调用到了操作系统的方法(这个说法有点不准确),然后是关于 Linux 阻塞队列的原理,有一个 __wait_event 方法,具体如下:
#define __wait_event(wq, condition)
       do {
               DEFINE_WAIT(__wait);

               for (;;) {
                       prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);
                       if (condition)
                               break;
                       schedule();
               }
               finish_wait(&wq, &__wait);
       } while (0)

然后就没有其它资料了,可以看到里面有一个死循环,所以底层是会用循环来判断是否满足条件?(感觉并没有到底层)那么这也是变相消耗系统资源了啊,有点像回调
2. 如果底层是使用循环来判断,那么例如定时器,操作系统是如何管理时间的?如果也是有循环,那么时间粒度是多少,1 毫秒?如果不是,如何判断时间到达?

感觉最底层一定不是我所猜测的这样,应该是有特殊的数据结构和方法。最后,不要说什么操作系统内核完成,我就是想学习一下原理,就算是汇编也想研究下,有懂的大佬能解下惑吗?或者给几个相关技术名词。

7688 次点击
所在节点    程序员
80 条回复
Michaelssss
2019-12-26 12:29:26 +08:00
@lxk11153
实质上阻塞机制就是 CPU 循环+中断+特定的数据结构
squancher
2019-12-26 12:31:29 +08:00
@lxk11153 我觉得也是这么个理,好奇操作系统对那么多指令一直循环判断是怎么保持低资源的
nevin47
2019-12-26 12:32:40 +08:00
@lxk11153 #19 可以这么去简单理解。


@dongyx #20 内核一般不会去轮训寄存器的,那种开销太大了,大部分时候会和中断配合起来
Michaelssss
2019-12-26 12:32:51 +08:00
@Michaelssss
然后特定的数据结构以 Linux 为例,请看 https://github.com/torvalds/linux/blob/master/include/linux/sched.h
因为 Linux 进程和线程我记得是相同的数据结构
nevin47
2019-12-26 12:37:49 +08:00
@squancher #22 你要先认识到……CPU 的循环是 Cycle,不是上层语言的 for。
每一次 Cycle 干的事儿可以是一样的,开销是固定的。操作系统是配合中断+轮训来实现的

要是全靠软件循环,计算机早炸了……
caowentao
2019-12-26 12:44:12 +08:00
条件满足是一个时刻,需要通过采样获得,采样频率越高,获得的时刻越精准,响应实时性越高。循环查询展开是一个时域离散采样过程。
squancher
2019-12-26 12:47:41 +08:00
@nevin47 但是中断就意味着恢复,谁来干恢复这个事,要做到达到条件就立刻恢复,不应该实时监控、不断轮询吗?
zwhfly
2019-12-26 12:51:21 +08:00
@squancher 让中断源达到条件时中断啊
squancher
2019-12-26 12:54:06 +08:00
@zwhfly 就是这个问题,上面问过了,怎样判断条件,能做到实时,快速反应
x1596357
2019-12-26 12:57:45 +08:00
@squancher 还是看看操作系统原理处理器调度一章比较好,这样你能系统的知道究竟是怎么工作的。论坛里一人几句也只是碎片的知识。轮询是一种忙等待策略,非常浪费资源。实际使用的是中断来的时候检测条件,比如你等待网络流量,网卡电信号接受到帧,网卡中断,内核解包,发现这个包就是你在等的,唤醒你的进程,然后就处理完了一个包,继续等待其他包。所谓的等待,在用户空间,进程看来,是失去处理器时间,实际上处理器会去执行其他程序。至于中断切换恢复上下文,这也是调度器的工作,保存恢复寄存器状态等。
GeruzoniAnsasu
2019-12-26 13:04:50 +08:00
@squancher

> 就是这个问题,上面问过了,怎样判断条件,能做到实时,快速反应





不是“实时”的。
协程你理解吧,协程状态变化不是“实时的”对吧,而是被等待 routine 状态改变的时候调度器把等待进程重新设为可调度而已


进程一样的,操作系统判断被等事件状态可改变时把状态修改(为完成),同时把在等待这个事件的所有进程重新设为可调度,下次调度时就能恢复它们的执行流程



顺带一提,正因为 linux 调度器算法机制不能做到“实时”,所以 linux 并不是一个实时操作系统。RTOS 需要有硬件机制来直接通知内核立即切换进程状态并调度目的进程
codehz
2019-12-26 13:05:17 +08:00
@squancher 中断是硬件实现,等于强行跳转到另一个执行逻辑(所谓中断处理函数,实际并不是手动调用过去的,而是硬件暴力跳转过去),软件层面无法改变也没法预测
codehz
2019-12-26 13:09:19 +08:00
判断的过程有非常多的选项,对于同步的系统调用来说,最简单了,就是遍历一个候选列表,然后一个一个判断过去(没错,就是链表)
你以为的实时只是假象,看起来很快,但起码有个几千个时钟周期的“浪费”,根本不是实时的
squancher
2019-12-26 13:13:19 +08:00
@GeruzoniAnsasu 你说的我大概理解,我关心的是对于“操作系统判断被等事件状态”这个过程。
GeruzoniAnsasu
2019-12-26 13:13:26 +08:00
@squancher 假设我们实现一个慢悠悠的,没有优先级的,分片很长的调度方法


那,阻塞这件事就会变成( A 等待 B 进程,系统有 ABCD4 个进程)
1. A 进程进入等待状态,调度器把 A 关联到 B,A 变为不可调度
2. 调度 B 进程,B 进程获得时间片,跑 1 秒,任务没结束。
3. 调度 C 进程,C 进程获得时间片,跑 1 秒
4. 调度 D 进程,D 进程获得时间片,跑 1 秒
5. 调度 A 进程,A 进程不能调度,继续选下一个
6. 调度 B 进程,B 进程获得时间片,跑 1 秒任务结束
7. 调度器发现 B 进程结束了,遍历正在等 B 的进程,发现 A,A 设为可调度
8. 调度 C 进程
9. 调度 D 进程
10. 调度 A 进程,A 进程获得时间片,取得 B 状态,跑 1 秒
11. 调度 B 进程,B 进程所有关联的等待者已不再等待,可以卸载 B 进程
12. 调度 C 进程

……
GeruzoniAnsasu
2019-12-26 13:14:22 +08:00
@squancher 内核中有专门结构,进程内会通过 api 来通知内核修改内核对象的值。
zwhfly
2019-12-26 13:15:35 +08:00
@squancher 什么是中断?中断是指 CPU 停止执行一段程序,转而执行另一段程序。注意后一句同样重要,中断不仅可以是一个结束,还可以是一个开始。

比如读文件,一个典型的阻塞操作,从用户层到文件系统到驱动,一路会注册等待链,到最后给到 比如 AHCI 控制器,AHCI 控制器是硬件外设,在背后和硬盘间一通骚操作交换数据,这个过程和 CPU 无关,从用户线程到文件系统到驱动啥都不用干(死循环都不用),AHCI 控制器把数据准备好后给 CPU 发中断信号,CPU 收到中断信号就能执行“中断处理程序”,这时候这个中断处理程序就能异步恢复一些东西了,刚才注册的等待链就是响应链,一层一层最终让用户态代码继续执行。
GeruzoniAnsasu
2019-12-26 13:16:26 +08:00
@squancher 状态改变是主动的,实时发生的,但检测状态改变,不是。

或者说 上面用户态的绝大多数情况都不需要实时感知直接触发回调
FrankHB
2019-12-26 13:18:57 +08:00
操作系统不需要实现如何实时反应。典型的分时系统反而有延迟,还就不是实时的。
真正需要实时响应的场合由硬件实现保证。
处理器的中断是可以异步触发的,中断服务例程也是硬件原生支持的异步调用。发生中断时,控制如何转移到中断服务例程根本就不用操作系统关心(操作系统看到的就是硬件自己把内部状态改了,接下来执行到了不同的位置)。操作系统需要做的,是在初始化时指定处理中断的逻辑,以及在此之上实现调度器。
caowentao
2019-12-26 13:19:49 +08:00
1.实时速度有上限,不会超过工作主频。
2.楼主给出的__wait_event 方法已经是操作系统底层实现逻辑了。
3.软件信号事件,查询开销是必须的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/632449

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX