莱纳斯·托瓦兹 (torvalds@cs.helsinki.fi)
1996 年 8 月 6 日星期二 12:47:31 +0300 (EET DST)
消息排序方式:[日期][主题][主题][作者]
下一条消息:Bernd P. Ziller:“Re: Oops in get_hash_table”
上一条消息:Linus Torvalds:“Re:I/O 请求排序”
1996 年 8 月 5 日星期一,Peter P. Eiserloh 写道:
我们需要保持一个清晰的线程概念。太多人
似乎将线程与进程混淆了。以下讨论
不反映linux当前的状态,而是一个
尝试保持高水平的讨论。
不!
没有理由认为“线程”和“进程”是
单独的实体。这就是传统上的做法,但我
个人认为这样想是大错特错。唯一的
这样想的理由是历史包袱。
线程和进程实际上只是一件事:一个“上下文
执行”。试图人为区分不同的情况只是
自我限制。
“执行环境”,在此称为 COE,只是集团
该 COE 的所有状态。该状态包括 CPU 之类的东西
状态(寄存器等),MMU 状态(页面映射),权限状态
(uid, gid) 和各种“通信状态”(打开文件、信号
处理程序等)。传统上,“线程”和“线程”之间的区别
“进程”主要是线程具有 CPU 状态(+ 可能
其他一些最小状态),而所有其他上下文都来自
过程。然而,这只是
一种 划分 COE 总状态的方法,没有什么可以说它是正确的方法。限制自己
那种形象简直就是愚蠢。
Linux 对此的思考方式(以及我希望事情发生的方式)是
没有“进程”或“线程”之类的东西。有
只有整个 COE(Linux 称为“任务”)。不同的COE
可以彼此共享部分上下文,并且其中一个 子集
共享是传统的“线程”/“进程”设置,但是
真的应该被视为只是一个子集(它是一个重要的子集,但
这种重要性不是来自设计,而是来自标准:我们显然
想在 Linux 上运行符合标准的线程程序
也)。
简而言之:不要围绕线程/进程的思维方式进行设计。这
内核应该围绕COE的思维方式设计,然后
pthreads library 可以将有限的 pthreads 接口导出给用户
谁想使用这种方式查看 COE。
作为一个例子,当您将 COE 视为可能时
反对线程/进程:
- 您可以执行外部“cd”程序,这在 UNIX 和/或进程/线程中传统上是不可能的(愚蠢的示例,但想法
是你可以拥有不限于这些类型的“模块”
传统的 UNIX/线程设置)。做一个:
克隆(CLONE_VM|CLONE_FS);
child: execve("external-cd");
/* "execve()" 将解除 VM 的关联,所以我们唯一的原因是
使用 CLONE_VM 是为了让克隆行为更快 */
- 您可以自然地执行“vfork()”(它需要最少的内核支持,但这种支持非常适合 CUA 的思维方式):
克隆(CLONE_VM);
child:继续运行,最终execve()
妈妈:等待执行
克隆(CLONE_FILES);
child:打开文件描述符等
妈妈:使用孩子打开的fd和vv。
上述所有工作都是因为您不受线程/进程的束缚
思维方式。以 Web 服务器为例,其中 CGI
脚本作为“执行线程”完成。你不能这样做
传统线程,因为传统线程总是要共享
整个地址空间,所以你必须链接你曾经的所有东西
想在网络服务器本身做(一个“线程”不能运行另一个
可执行)。
将此视为“执行上下文”问题,您的
任务现在可以选择执行外部程序(= 将
来自父母的地址空间)等,如果他们愿意,或者他们可以
示例与文件的父 except 共享所有内容
描述符(以便子“线程”可以打开大量文件,而无需
父母需要担心它们:它们会自动关闭
子“线程”退出,并且它不会用完父级中的 fd)。
例如,考虑一个线程化的“inetd”。你想要低开销
fork+exec,所以用 Linux 的方式你可以代替使用“fork()”
您编写一个多线程 inetd,其中创建每个线程
只是 CLONE_VM(共享地址空间,但不共享文件描述符
等等)。如果它是外部服务(rlogind,
例如),或者它可能是内部 inetd 服务之一
(echo, timeofday) 在这种情况下,它只是做它的事情并退出。
“线程”/“进程”无法做到这一点。
莱纳斯