Loading... # 0x01 我们通常都认为 > 操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位 但是今天刷知乎看到有人贴 Linus 大神对线程和进程在内核层面的解释,觉得角度挺棒的,这里就简单的翻译一下~ 原文地址:[Linux-Kernel Archive: Re: proc fs and shared pids](http://lkml.iu.edu/hypermail/linux/kernel/9608/0191.html) # 中英对照翻译 On Mon, 5 Aug 1996, Peter P. Eiserloh wrote: 1996年8月5日星期一,Peter P. Eiserloh写道: > We need to keep a clear the concept of threads. Too many people seem to confuse a thread with a process. The following discussion does not reflect the current state of linux, but rather is an attempt to stay at a high level discussion. > > 我们需要保持一个清晰的线程概念。太多的人似乎把线程和进程混为一谈。下面的讨论并不反映Linux的现状,而只是一个试图停留在高水平的讨论。 No! 不是这样的! There is NO reason to think that "threads" and "processes" are separate entities. That's how it's traditionally done, but I personally think it's a major mistake to think that way. The only reason to think that way is historical baggage. 没有理由认为 "线程 "和 "进程 "是独立的实体。传统上是这样认为的,但我个人认为这样想是个大错误。这样想的唯一原因是由于历史包袱。 Both threads and processes are really just one thing: a "context of execution". Trying to artificially distinguish different cases is just self-limiting. 线程和进程其实都是"执行的上下文(context of execution)"。试图人为地区分不同的情况是不对的(自我限制的?)。 A "context of execution", hereby called COE, is just the conglomerate of all the state of that COE. That state includes things like CPU state (registers etc), MMU state (page mappings), permission state (uid, gid) and various "communication states" (open files, signal handlers etc). 一个 "执行的上下文",在此称为COE,只是该COE所有状态的集合体。该COE的所有状态。这种状态包括诸如CPU状态(寄存器等),MMU状态(页面映射),权限状态(UID,GID )以及各种 "通信状态"(打开的文件、信号处理程序等)。 Traditionally, the difference between a "thread" and a "process" has been mainly that a threads has CPU state (+ possibly some other minimal state), while all the other context comes from the process. However, that's just one_ way of dividing up the total state of the COE, and there is nothing that says that it's the right way to do it. Limiting yourself to that kind of image is just plain stupid. 传统上,"线程 "和 "进程 "之间的区别主要是线程有CPU状态(可能还有其他一些最小状态),而所有其他的上下文都来自于进程。然而,这只是划分COE总状态的一种方式,并没有说这是正确的方式。把自己限制在这种形象上,实在是太愚蠢了。 The way Linux thinks about this (and the way I want things to work) is that there _is_ no such thing as a "process" or a "thread". There is only the totality of the COE (called "task" by Linux). Different COE's can share parts of their context with each other, and one _subset_ of that sharing is the traditional "thread"/"process" setup, but that should really be seen as ONLY a subset (it's an important subset, but that importance comes not from design, but from standards: we obviusly want to run standards-conforming threads programs on top of Linux too). Linux对这个问题(以及我希望事情的运作方式)的思考是,不存在 "进程"或 "线程"这样的东西。只有COE的整体(Linux称之为 "任务")。不同的COE可以互相分享他们的上下文,这种分享的一个子集就是传统的 "线程/进程"设置,但这真的应该被看作只是一个子集(它是一个重要的子集,但这种重要性不是来自设计,而是来自标准:我们显然也想在Linux上面运行符合标准的线程程序)。 In short: do NOT design around the thread/process way of thinking. The kernel should be designed around the COE way of thinking, and then the pthreads _library_ can export the limited pthreads interface to users who want to use that way of looking at COE's. 简而言之:不要围绕线程/进程的思维方式进行设计。内核应该围绕COE的思维方式来设计,然后由 pthreads _library 将有限的 [pthreads](https://software.intel.com/content/www/cn/zh/develop/articles/threading-models-for-high-performance-computing-pthreads-or-openmp.html) 接口输出给那些想使用COE方式的用户。 > Pthreads 是什么? > > Pthreads 指定 API 来处理线程要求的大部分行为。这些行为包括创建和终止线程、等待线程完成、以及管理线程之间的交互。 > > **具体详情点上门 pthreads 的链接** Just as an example of what becomes possible when you think COE as opposed to thread/process: 举个:chestnut:,我们不妨设想一下,当COE与线程/进程相反时,会发生什么: - You can do a external "cd" program, something that is traditionally impossible in UNIX and/or process/thread (silly example, but the idea is that you can have these kinds of "modules" that aren't limited to the traditional UNIX/threads setup). Do a: - 你可以做一个外部的 "cd "程序,这是传统上在UNIX 和/或 进程/线程中不可能做到的(愚蠢的例子,但 想法是你可以有这类 "模块",不限于传统UNIX/线程的设置)。类似: ```bash clone(CLONE_VM|CLONE_FS); child: execve("external-cd"); /* the "execve()" will disassociate the VM, so the only reason we used CLONE_VM was to make the act of cloning faster */ /*execve() "将解除虚拟机的关联。所以我们使用CLONE_VM的唯一原因是为了使克隆行为更快。*/ ``` - You can do "vfork()" naturally (it meeds minimal kernel support, butthat support fits the CUA way of thinking perfectly): - 你可以自然地做 "vfork()"(它需要最小的内核支持,但这种支持非常符合CUA的思维方式): ```bash clone(CLONE_VM); /* child: continue to run, eventually execve() mother: wait for execve */ /* child:继续运行,最终execve() mother:等待execve */ ``` All of the above work because you aren't tied to the thread/process way of thinking. Think of a web server for example, where the CGI scripts are done as "threads of execution". You can't do that with traditional threads, because traditional threads always have to share the whole address space, so you'd have to link in everything you ever wanted to do in the web server itself (a "thread" can't run another executable). 上述所有的工作都是因为你没有被线程/进程的思维方式所束缚。例如,想想一个网络服务器,其中的CGI脚本是作为 "执行线程 "完成的。你不能用传统的线程来做,因为传统的线程总是要分享整个地址空间,所以你必须把所有你想做的事情都链接到网络服务器本身(一个 "线程 "不能运行另一个可执行文件)。 Thinking of this as a "context of execution" problem instead, your tasks can now chose to execute external programs (= separate the address space from the parent) etc if they want to, or they can for example share everything with the parent _except_ for the file descriptors (so that the sub "threads" can open lots of files without the parent needing to worry about them: they close automatically when the sub-"thread" exits, and it doesn't use up fd's in the parent). 把这个问题看成是一个 "执行的上下文 "的问题,你的任务现在可以选择执行外部程序(=与父代的地址空间分开)等,如果他们想的话,或者他们可以与父代共享除了文件描述符的一切,(所以子 "线程 "可以打开很多文件,而父代不需要担心它们:当子 "线程 "退出时,它们自动关闭,而且它不会占用父代的fd)。 Think of a threaded "inetd", for example. You want low overhead fork+exec, so with the Linux way you can instead of using a "fork()" you write a multi-threaded inetd where each thread is created with just CLONE_VM (share address space, but don't share file descriptors etc). Then the child can execve if it was a external service (rlogind, for example), or maybe it was one of the internal inetd services (echo, timeofday) in which case it just does it's thing and exits. 比如说,想想一个线程的 "inetd"。你想要低开销的fork+exec,所以用Linux的方式,你可以不使用 "fork()",而是写一个多线程的inetd,每个线程只用CLONE_VM创建(共享地址空间,但不共享文件描述符等)。然后,如果是一个外部服务(例如rlogind),子线程可以退出,或者是一个内部的inetd服务(echo,timeofday),在这种情况下,它只是做它的事情并退出。 You can't do that with "thread"/"process". 你不能用 "线程/进程 "这样做。 Linus # 个人理解 <div class="tip inlineBlock warning"> 如果理解有误请务必在评论区告诉我 </div> 前半部分翻的比较认真,开始举例子的时候就看不太懂了,就开始机翻了... 学艺不精学艺不精:joy::joy::joy: 全文应该是针对操作系统内核设计解释的,个人对这篇文章的理解是:Linus 大神认为不要人为的把进程和线程划分为两个概念,而把他们都当做“上下文”,只是他们两者所处的上下文语义不一样,即 CPU 执行任务时,需要线程提供的一些 CPU 执行时的一些状态(上下文),而进程则是有给线程提供一些共享的资源(也可以称作上下文),如内存空间、文件、socket等。 对于我们应用层开发来说,后台多线程比多进程的好处是减少资源分配释放的时间,在进程中可以缓存线程公用资源,如数据库连接池等。 最后修改:2021 年 07 月 09 日 01 : 20 PM © 允许规范转载 赞赏 如果觉得我的文章对你有用,请随意赞赏 赞赏作者 支付宝微信