如果系统调用和过程调用一样快,它会使内核级线程明显优于用户级线程吗?

Would it makes the kernel level thread clearly preferable to user level thread if system calls is as fast as procedure calls?

一些网络搜索结果告诉我,内核级线程唯一的不足是其管理(创建、切换、终止等)速度较慢。看来如果内核级线程上的操作全部通过系统调用,我的问题的答案就会成立。但是,我找了很多,想知道内核级线程的管理是不是都是通过系统调用来进行的,但是一无所获。而且我一直有一种直觉,这种管理应该由 OS 自动完成,因为只有 OS 知道在特定时间哪个线程适合 运行。所以程序员似乎不可能写一些显式的系统调用来管理线程。我很感激任何想法。

你的基本前提是错误的。在几乎所有有趣的体系结构中,系统调用都比过程调用慢得多。

感知的 cpu 吞吐量基于流水线、推测执行和提取。系统调用停止管道,使推测执行无效并停止推测提取,是存储和指令屏障,并可能刷新写入 fifo。

因此,处理器在系统调用周围减慢到其“规范”速度,然后加速回到系统调用 return,然后它会做同样的事情。

优化这一领域的尝试已经产生了许多以虚构的詹姆斯邦德组织命名的论文,并且没有足够的安抚道歉来自不够尴尬的 cpu 产品经理。 Google 以幽灵为例,然后点击相关链接。

系统调用的其他开销

30 多年前,一些聪明人写了一篇关于最小特权的论文。从概念上讲,这是一个惊人的。基本前提是无论您的程序在做什么,它都应该以尽可能少的权限执行。

如果您的程序正在反转数组,根据最小权限的概念,它不应该能够禁用中断。禁用中断会导致非常难以诊断的系统故障。简单的用户代码不应该有这个能力。

userkernel 执行模式的概念从早期的计算机系统演变而来,并且(iax32 / 80286 ) 越来越多地显示出它们在连接的计算机环境中的不足。在某个时间点你可以说 "this is a single user system";但是 IoT 笨蛋让一切都成为多用户。

最低权限坚持认为所有代码都应该以完成手头任务所需的最低权限执行。因此,内核中不应包含绝对不需要的内容。如果您认为这是一个激进的想法,那么在 Ken Thompson 1977 年(?)关于 UNIX 内核的论文中,他也表达了完全相同的观点。

所以不,将垃圾放入内核仅意味着您无缘无故地增加了攻击面。尝试从暴露最小风险的角度思考,它会带来更好的软件和更好的睡眠。

Some web searching results told me that the only deficiency of kernel-level thread is the slow speed of its management(create, switch, terminate, etc.).

没那么简单。要理解,请考虑导致任务切换的原因。这是一个(部分)列表:

  • 设备告诉设备驱动程序操作已完成(一些数据已到达等)导致正在等待该操作的线程解除阻塞,然后抢占当前 运行 线程。对于这种情况,当您发现需要任务切换时,您是 运行 内核代码,因此内核任务切换速度更快。

  • 时间已经过去了;要么导致 "end of time slice" 任务切换,要么导致休眠线程解除阻塞并抢占。对于这种情况,当您发现需要任务切换时,您是 运行 内核代码,因此内核任务切换速度更快。

  • 线程访问了当前不可访问的虚拟内存,触发内核的页面错误处理程序发现当前任务必须等待内核从交换中获取数据space 或来自文件(如果虚拟内存是内存映射文件的一部分),或者必须等待内核通过发送其他页面进行交换来释放 RAM space(如果虚拟内存涉及某种"copy on write");导致任务切换,因为当前 运行 任务无法继续。对于这种情况,当您发现需要任务切换时,您是 运行 内核代码,因此内核任务切换速度更快。

  • 正在创建一个新进程,其初始线程抢占当前 运行 线程。对于这种情况,当您发现需要任务切换时,您是 运行 内核代码,因此内核任务切换速度更快。

  • 当前 运行 线程要求内核对文件执行某些操作,内核得到 "VFS cache miss" 阻止在没有任何任务切换的情况下执行请求。对于这种情况,当您发现需要任务切换时,您是 运行 内核代码,因此内核任务切换速度更快。

  • 当前运行线程释放互斥体或发送一些数据(例如使用管道或套接字);导致属于不同进程的线程解除阻塞和抢占。对于这种情况,当您发现需要任务切换时,您是 运行 内核代码,因此内核任务切换速度更快。

  • 当前运行线程释放互斥体或发送一些数据(例如使用管道或套接字);导致属于同一进程的线程解除阻塞并抢占。对于这种情况,你是 运行 user-space 代码,当你发现需要任务切换时,所以理论上 user-space 任务切换更快,但实际上它可以很容易成为设计不佳的指标(使用太多线程 and/or 太多锁争用)。

  • 正在为同一进程创建一个新线程;并且新线程抢占当前 运行 线程。对于这种情况,你是 运行 user-space 代码,当你发现需要一个任务切换时,所以在 user-space 中任务切换更快;但只有在内核未被通知的情况下(例如 "top" 等实用程序可以正确显示线程的详细信息)——如果内核被通知,那么任务切换发生的位置并没有太大区别。

对于大多数软件(不使用很多线程);在内核中进行任务切换更快。当然,它也(希望)与性能无关(因为与花在其他工作上的时间相比,切换任务所花费的时间应该很少)。

And I always have an instinct that such management should be done by the OS automatically because only OS knows which thread would be suitable to run at a specific time.

是;但可能不是你想的那样。

user-space 线程的另一个问题(除了使大多数任务切换变慢之外)是它不能支持全局线程优先级而不会成为严重的安全灾难。具体来说;一个进程无法知道它自己的线程的优先级是否高于或低于属于不同进程的线程(除非它有关于整个 OS 的所有线程的信息,这是正常进程不应该知道的信息相信拥有);所以 user-space 线程导致浪费 CPU 时间做不重要的工作(对于一个进程),而有重要的工作要做(对于不同的进程)。

user-space 线程的另一个问题是(对于某些 CPUs - 例如大多数 80x86 CPUs)CPUs 不是独立的,并且调度可能涉及电源管理决策。举些例子;大多数 80x86 CPUs 都有超线程(其中一个内核由 2 个逻辑处理器共享),其中智能调度程序可能会说 "one logical processor in the core is running a high priority/important thread, so the other logical processor in the same core should not run a low priority/unimportant thread because that would make the important work slower";大多数 80x86 CPU 有 "turbo boost"(具有类似的 "don't let low priority threads ruin the turbo-boost/performance of high priority thread" 可能性);大多数 CPU 都有热管理(调度程序可能会说 "Hey, these threads are all low priority, so let's underclock the CPU so that it cools down and can go faster later (has more thermal headroom) when there's high priority/more important work to do!")。

Would it makes the kernel level thread clearly preferable to user level thread if system calls is as fast as procedure calls?

如果系统调用和普通过程调用一样快,那么用户space线程和内核线程之间的性能差异就会消失(但是用户space线程的所有其他问题都会保持)。然而,系统调用比普通过程调用慢的原因是它们通过了一种"isolation barrier"(将内核代码和数据与恶意用户-space代码隔离);因此,要使系统调用与普通过程调用一样快,您必须摆脱隔离(有效地将内核变成一种可以动态链接的 "global shared library"),但如果没有这种隔离,您将拥有极端的安全灾难。换一种说法;要获得可接受的安全性,系统调用必须比正常过程调用慢。