V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
LeeReamond
V2EX  ›  问与答

都是切换,为什么系统调用比进程切换的速度快?

  •  
  •   LeeReamond · 2021-04-16 03:22:54 +08:00 via Android · 1550 次点击
    这是一个创建于 1347 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题,理论上来说系统调用也经历了进程切换的过程,从用户程序切换到了系统进程 cpu 层面同样有一个保存,切换,恢复的过程。但是之前看过一些文章做过实验,比如写一个 c 的小程序,让 a 线程唤醒 b 线程后立刻挂起,直到被唤醒,如此循环,以实现人工的重复切换线程的操作,最后实验结果是在 linux 系统下切换线程每次大概需要 3.5 微秒,这个值比系统调用高二十倍以上。

    系统调用为什么可以这么快呢?
    6 条回复    2021-04-16 14:41:38 +08:00
    Nitroethane
        1
    Nitroethane  
       2021-04-16 07:43:28 +08:00 via iPhone
    “理论上来说系统调用也经历了进程切换的过程”,先问是不是,再问为什么。Linux 下系统调用的实现,从最早的使用 int 指令触发中断执行系统调用,还是后来的使用专有的系统调用指令如 sysenter,只是从用户态切换到内核态而已,进入系统调用并不需要很多操作。
    对于进程切换来说,所有和进程上下文有关的东西都要修改,例如修改大多数寄存器的值等等。
    Linux 内核中没有线程的概念。内核代码注释里,thread 、task 、process 三个词经常混用,都指的是 process 。线程是通过标准库在用户态通过 clone 系统调用实现的。也就是说,Linux 下线程是共享某些系统资源的轻量级进程。线程切换的代价比进程切换的代价要小得多。
    至于你看的这个实验,建议发出来让大家看看。
    最后,从你对问题的描述来看,建议恶补一下操作系统的知识。
    上面描述可能有一些不准确的地方,如果错误请指出
    LeeReamond
        2
    LeeReamond  
    OP
       2021-04-16 08:02:28 +08:00
    @Nitroethane
    文章地址
    https://zhuanlan.zhihu.com/p/80206565
    https://zhuanlan.zhihu.com/p/79772089

    感谢回复,不过恶补操作系统知识是正确的废话,从 V2EX 发帖提问状况来看,了解相关知识能回答我的人似乎并不占多数,我也同样作为大多数的一员,处于学习无门的状态。

    我读你的回复有一些疑惑,我目前理解的系统调用的过程,比如使用 int0x80 触发中断执行系统调用的方式,int $0x80 是一条汇编指令,CPU 读到这条指令之后会保存当前线程的寄存器等等,然后执行对应的系统调用逻辑,之后再恢复当前线程的寄存器等等,继续任务。不知道上述理解是否准确。从内存角度来说,系统调用的相关资源应该也不存在于某一线程能映射到的虚拟内存的范围内。那么这个备份状态-执行另一个内存空间里的代码-恢复状态的过程不就是一次进程间切换么。
    Nitroethane
        3
    Nitroethane  
       2021-04-16 09:09:32 +08:00   ❤️ 3
    就拿 int 0x80 中断实现系统调用来说吧,Linux 内核版本 2.6.32 。中断门在 trap_init() 函数中初始化,set_system_trap_gate(SYSCALL_VECTOR, &system_call) ( https://elixir.bootlin.com/linux/v2.6.32/source/arch/x86/kernel/traps.c#L963 )。从这里可以看出,触发 0x80 号中断时会执行 system_call 函数。而 system_call 函数时定义在 /arch/x86/kernel/entry_64.S 中的汇编代码( https://elixir.bootlin.com/linux/v2.6.32/source/arch/x86/kernel/entry_64.S#L455 )。看看这个函数就知道为了进入系统调用做了哪些操作。
    再看看进程切换。进程切换发生在进程被调度的时候,由 context_switch() 函数实现。其中最关键的 switch_mm() 和 switch_to() 函数完成了主要的工作。
    通过比较内核代码,你看看哪个简单,哪个麻烦。


    不要觉得没人回答你的问题就是他们不懂。我开始看到你这个问题的时候就觉得你对一些基本的操作系统概念不熟悉,表述问题太多。如果不是为了复习一下以前的知识,我是不会回答你的问题的。其实请教问题的时候可以稍微虚心一点。

    至于怎样学习操作系统,首先你对一些基本的概念了解的怎样?例如操作系统的目的、出现的原因,以及操作系统的基本组成部分,如进程管理和调度、内存管理、文件系统、进程间通信等等。然后每个组成部分的基本概念是否熟悉,例如对于进程管理来说,操作系统通过 PCB 来描述每个进程,等等。
    基本概念了解之后,带着这些具体的疑问结合相关的书和文章去看内核源码。就拿这个问题来说,首先要了解系统调用的具体实现,先去 Google 一些文章,了解大致的实现。然后边读书边看源码去深入研究。同时用一些内核调试技术去亲手实践一下。
    xumng123
        4
    xumng123  
       2021-04-16 09:09:46 +08:00 via iPhone
    一直在找这方面的测评数据,目前没有找到有用的。
    只要关注:1. 任务切换的延迟; 2. 函数压栈出栈延迟。
    LeeReamond
        5
    LeeReamond  
    OP
       2021-04-16 09:37:48 +08:00
    @Nitroethane 感谢回复,很遗憾我的水平不足以阅读 linux 的汇编源码,你提供的定位对我日后的学习找资料等很有帮助,但目前我不能读懂含义,所以我来论坛发帖希望有大佬能用自然语言描述两者的工作的主要区别,我也相信这个区别应该就是效率区别产生的原因。
    ch2
        6
    ch2  
       2021-04-16 14:41:38 +08:00
    那篇文章不是说了吗,系统调用耗时是不稳定的,最快 200ns,最慢十几微秒。进程切换是固定的几微秒
    进程切换置换了进程上下文,但是系统调用并没有发生进程切换
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1814 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:18 · PVG 00:18 · LAX 08:18 · JFK 11:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.