Unix/Linux fork前传

课程推荐:Linux开发工程师--学习猿地精品课程

fork的由来

fork的思想在UNIX出现几年前就出现了,时间大概是1963年,这比UNIX在PDP-7上的第一个版本早了6年。

1963年,计算机科学家Melvin Conway(以Conway’s Law闻名于世)写下一篇论文,正式提出了fork思想,该论文链接:A Multiprocessor System Design:

https://archive.org/details/AMultiprocessorSystemDesignConway1963/page/n7

fork的思想最初是Conway作为一种 多处理器并行 的方案提出来的,这个想法非常有意思。简而言之,fork思想来源于流程图。
我们看一个普通的流程图:
file

你看,流程图的分枝处,fork-叉子,多么形象!

一个流程图上的分支点分裂出来的分支显然是逻辑独立的,这便是可并行的前提,于是它们便可以表现为不同的 处理进程(process) 的形式,当时的表达还只是“process”这个术语,它还不是现代操作系统意义上的“进程”的概念。

join同步点表现为多个并行处理的进程由于某种原因不得不同步的点,也就是多个并行流程汇合的点,直到现在,在多线程编程中,这个点依然叫join。比如Java Thread的join方法以及pthread库的pthread_join函数。

广义来讲,join也表示诸如临界区等必须串行通过的点, 减少join点的数量将会提高并行的效率。

我们来看看Conway论文中关于fork的原始图示:
file

Conway在论文中的另一个创举是,他将处理进程(也就是后来操作系统中的process的概念)以及执行该进程的处理器(即CPU核)分离了开来,抽象出了schedule层。

大意是说, “只要满足系统中的活动处理器数量是总处理器数量和并行处理进程的最小值即可。” 这意味着调度程序可以将多处理器系统的所有处理器和系统所有处理进程分别看作是统一的资源池和消费者,执行统一调度:
file
在UNIX引入fork之后,这种多处理器并行的设计思想就深入到了UNIX的核心。这个思想最终也影响了UNIX以及后来的Linux,直到现在。

关于这个设计思想为什么可以影响UNIX这么久,我想和Conway本人的“Conway’s law”不无关系,在这个law中,他提到:Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.

好了,fork本身的由来我们已经了解,就像做菜一样,现在我们把它放在一边备用。

花开两朵,各表一枝。接下来看UNIX fork的另一个脉络。

早期UNIX的覆盖(overlaying)技术
1969年最初的UNIX用一种在现在看来非常奇怪的方式运行。

一般的资料都是从UNIX v6版本开始讲起,那个版本已经是比较 “现代” 的版本了,所以很少有人能看到最初的UNIX是什么样子的。即便是能查阅到的1970年的PDP-7上运行的UNIX源码,也是引入fork之后的版本,在那之前的最原始版本几乎找不到了(你可能会说,那时的UNIX不叫UNIX,but who cares…)。

1969年的汤普森版UNIX超级简陋,这可以在Dennis M. Ritchie的一篇论文中见一斑:The Evolution of the Unix Time-sharing System:

http://www.read.seas.harvard.edu/~kohler/class/aosref/ritchie84evolution.pdf

最初的UNIX是一个分时系统,它只有两个shell进程,分别属于两个终端:
file

分时系统最初并不是基于进程分时的,那时根本还没有完整的进程的概念,分时系统是针对终端分时的,而操作员坐在终端前,为了让每个操作员在操作过程中感觉上是在独占机器资源,每个终端享受一段时间的时间片,在该时间片内,该终端前的操作员完全享受机器,但是为了公平,超过了时间片,时间片就要给另一个终端。

就是这样,最初的UNIX为了体现分时特性,实现了最少的两个终端。注意,最初的UNIX没有fork,没有exec,甚至没有多进程的概念,为了实现分时,系统中仅有两个朴素的shell进程。

事实上,最初的UNIX用只有两个元素的表来容纳所有进程(显然,这看起来好笑…),当然,这里的 “表” 的概念也是抽象的朴素概念,因为当时的系统是用PDP-7的汇编写的,还没有后来C语言数据结构。

我们现在考虑其中一个终端的shell进程如何工作。马上问题就来了, 这个shell进程如何执行别的命令程序??

如果说系统中最多只能容纳两个进程,一个终端只有一个shell进程的话,当该终端的shell进程执行其它命令程序时,它自己怎么办?这个问题得思考一会儿…

注意,不要用现代的眼光去评价1969年的初版UNIX,按照现代的眼光,执行一个程序必然要生成一个新的进程,显然这在初版UNIX中并不正确。

答案是根本不用产生新的进程,直接将命令程序的代码载入内存并 覆盖 掉shell进程的代码即可!当命令执行完后,再用shell的代码覆盖掉命令程序的代码,针对单独的终端,系统其实一直在执行下面的覆盖循环(摘自论文的Process control 章节):
file

然而,在fork被引入UNIX之前,事实就是这样。一个终端上一直都是那一个进程,一会儿它执行shell的代码,一会儿它执行具体命令程序的代码,以下是一个覆盖程序的结构(图片来自《FreeBSD操作系统设计与实现》一书):
file

然而,当时毕竟还没有将这个逻辑封装成exec系统调用,这些都是每一个进程显式完成的:

对于shell执行命令程序而言,shell自己执行disk IO来载入命令程序覆盖掉自身;

对于命令程序执行结束时,exit调用内部执行disk IO载入shell程序。

exec逻辑是shell程序的一部分,由于它会被所有的命令程序所使用,该逻辑也被封装到了exit调用中。

fork引入UNIX前的表象
好了,目前为止,我们看完了两条线索:

1963年Melvin Conway提出了fork思想,作为在多处理器中并行执行进程的一个手段。

1969年汤普森版UNIX仅有两个shell进程,使用覆盖(overlaying)技术执行命令。

截止目前,我们看到的表象是:

汤普森版UNIX没有fork,没有exec,没有wait,仅有的库函数般的exit也和现在的exit系统调用大相径庭,显然汤普森版UNIX并非一个多进程系统,而只是一个可以跑的简陋的两终端分时系统!

UNIX fork的诞生
fork是如何引入UNIX的呢?

这还要从采用覆盖技术的汤普森版UNIX所固有的问题说起,还是看论文原文:
file
file
若要解决这些问题,很简单的方案汤普森都想到了:

保持shell进程的驻留而不是销毁。命令执行时,将其交换到磁盘便是了

很显然,命令程序是不能覆盖掉shell进程了。解决方案是使用 “交换” 技术。

交换技术和覆盖技术其实都是解决有限内存的多进程使用问题的,不同点在于方向不同:

覆盖技术指的是用不同的进程磁盘映像覆盖当前的进程内存映像。

交换技术指的是用将进程的内存映像交换到磁盘,载入一个别的进程磁盘映像。

使用交换技术解决覆盖的问题,意味着要创建新的进程:

在新的进程中执行命令程序。

UNIX需要进行改动,两个配额的进程表显然不够用了。当然,解决方案也并不麻烦:
file

要讲效率,创造不如抄袭,创建新进程的最直接的就是copy当前shell进程,在copy的新进程中执行覆盖,命令程序覆盖copy的新进程,而当前的终端shell进程则被交换到磁盘保得全身。

覆盖和交换相结合了,UNIX离现代化更近了一步!

确定了copy当前进程的方案后,进一步的问题是如何来copy进程。

现在要说回fork了。

Conway提出fork思想后,马上就有了fork的实现原型(正如Conway自己所说,他只是提出了一个可能造就存在的想法,并没有实现它),Project Genie算是实现fork比较完善的系统之一了。

Project Genie系统的fork不仅仅是盲目地copy进程,它对fork的过程拥有精细的控制权,比如分配多大的内存空间,copy哪些必要的资源等等。显然,Project Genie的fork是冲着Conway的多处理器并行逻辑去的。

还是那句话,创造不如抄袭,UNIX若想实现进程copy,有一个现成的模版就是Project Genie,但是Project Genie的fork对于UNIX太过复杂,太过精细化了,UNIX显然用不到这些精细的控制, UNIX仅仅是想让fork出来的新进程被覆盖,而不是让它去执行什么多处理器上的并行逻辑。

换句话说,UNIX只是借用了fork的copy逻辑的实现,来完成一件别的事。

于是,UNIX非常粗暴的实现了fork!即完全copy父进程,这就是直到现在我们依然在使用的fork系统调用:
file

取了个巧,奇技淫巧:

fork本来就不是让你用来覆盖新进程的,不然为何多此一举。fork是让你来分解程序流程得以并行处理的。

UNIX fork就此诞生!

我们再次回顾一下UNIX fork诞生之前的景象:
file

再来看看fork诞生之后的景象:
file
file
于是UNIX正式迈开了现代化建设的步伐,一直走到了今天。

UNIX fork-exec
关于exec,故事没什么好讲的,它事实上就是关于上述覆盖逻辑的封装,此后程序员不必自己写覆盖逻辑了,直接调用exec系统调用即可。

于是经典的UNIX fork-exec序列便形成了。

UNIX fork/exec/exit/wait
值得一提的是,fork被引入UNIX后,exit的语义发生了巨大的改变。

在原始的1969年汤普森版UNIX中,由于每一个终端有且仅有一个进程,这意味着覆盖永远是在shell程序和某个命令程序之间进行的:

shell执行命令A:命令程序A覆盖内存中的shell代码。

命令A执行结束:shell覆盖结束的命令A的内存代码。

然而,在fork被引入后,虽然shell执行某个命令依然是特定的命令程序覆盖fork出来的shell子进程,但是当命令执行完毕后,exit逻辑却不能再让shell覆盖当前命令程序了,因为shell从来就没有结束过,它作为父进程只是被交换到了磁盘而已(后来内存到了,可以容纳多个进程时,连交换都不需要了)。

那么exit将让谁来覆盖当前进程呢?

答案是不用覆盖,按照exit的字面意思,它只要结束自己就可以了。

本着 自己的资源自己管理的责任原则 exit只需要清理掉自己分配的资源即可。比如清理掉自己的内存空间以及一些其它的数据结构。

对于子进程本身而言,由于它是父进程生成的,所以它便由父进程来管理释放。于是经典的UNIX进程管理四件套正式形成:
file

(完)

原文摘自:https://blog.csdn.net/juS3Ve/article/details/100680779?utm_medium=distribute.pc_category.none-task-blog-new-16.nonecase&depth_1-utm_source=distribute.pc_category.none-task-blog-new-16.nonecase

Image placeholder
olver
未设置
  0人点赞

没有讨论,发表一下自己的看法吧

推荐文章
Linux/Unix 基础:什么是 Linux?

简单来讲,Linux是一个操作系统(OS)。我们都很熟悉其他操作系统,就像Microsoftwindows,AppleMacOS,iOS,Googleandroid,等等这些,linux就像它们一样,

Linux/Unix 基础:Linux 的历史

Linux的诞生 在1991年,来自芬兰Helsinki大学的学生LinusTorvalds认为市场上应该有一个比较统一的Unix版本,从此他就开始为这个项目奋斗。后来这个项目就成为了Linux操作系

Java 程序员眼中的 Linux_1.0.Linux 介绍

Linux介绍 Linux这个名字 Linux的Wiki介绍:http://zh.wikipedia.org/zh/Linux Linux也称:GNU/Linux,而其中GNU的全称又是:Gnu’sN

[Java 程序员眼中的 Linux] Linux 下常用压缩文件的解压、压缩

Linux下常用压缩文件的解压、压缩 常用压缩包解压命令整理 Linux后缀为.tar.gz格式的文件-解压 命令:tarzxvfXXXXXX.tar.gz Linux后缀为.bz2格式的文件-解压

笨办法 学Linux 安装Linux

Linux学习起步 Windows,VirtualBox虚拟机(.ova格式的预配置映像) 学习Linux你需要什么 VitualBox,虚拟机播放器。 putty,终端模拟器。 预配置的Virtua

别小瞧了 Linux,安卓、华为的自研系统,均源自 Linux!

众所周知,目前国内已有众多的国产系统,基本上均源自linux,以linux为基础进行二次开发。比如红旗linux、深度等等。但不知道为什么,一说起某系统是基于linux而来,很多网友就瞧不起,并且会觉

Linux Kernel Linux内核项目

推荐课程:Linux开发工程师--学习猿地--送七个上线商业项目 Linux是最受欢迎的自由电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统。Linux最早是由芬兰黑客林

Linux Libertine Linux字体

课程推荐:Linux开发工程师--学习猿地精品在线课 软件简介 出于对GNU/Linux发行版中所附带的字体不满,PhilippH.Poll于2003年9月启动了LinuxLibertine开放性字体

workerman源码-workerman启动流程

前面我们跟着代码看了一遍workerman的初始化流程.但对于如何监听端口.等操作还没有具体的实现.我们这次就来看一下.workerman是如何监听端口并运行的.runAll在前面我们初始化方法过后,

Linux Shell 脚本快速入门

shell脚本是在一个文件中写入一起执行的命令集。对于使用像dos操作系统的DOS,windows操作系统的bat,linux操作系统的files的人来说,这几乎都是相同的概念。你只需要把一串命令写

Linux 安装 Node.js

因为我用最简单yum命令安装node.js发现node的版本不是最新的所以自己手动安装了nodejs流程如下 进入服务器安装nodejs安装包 进入保存包的目录 $cddownload 下载二进制

Linux 安装 Node.js

因为我用最简单yum命令安装nodejs发现node的版本不是最新的所以自己手动安装了nodejs流程如下 进入服务器安装nodejs安装包 进入保存包的目录 $cddownload 下载二进制包

Linux Shell 脚本快速入门

shell脚本是在一个文件中写入一起执行的命令集。对于使用像dos操作系统的DOS,windows操作系统的bat,linux操作系统的files的人来说,这几乎都是相同的概念。你只需要把一串命令写入

Linux 文件同步工具之 rsync

学习背景 1.最近公司的项目在使用jenkins做自动化构建,因为jenkins在构建时是比较耗性能的,便单独使用了一台服务器做构建服务器。但是个人觉得这样成本过高,单独拿一台服务器来构建并且该服务器

笨办法学 Linux 学习文本编辑器--vim

Linux学习文本编辑器--vim 在Linux中,就像任何类Unix操作系统,一切都只是文件。而Unix哲学指出,配置文件必须是人类可读和可编辑的。在几乎所有的情况下,它们只是纯文本。所以,首先,你

笨办法学 Linux 初识less

#文本浏览器,少即是多 现在你可以编辑文本文件,这很好。但是如果你只想查看一个文本文件呢?当然,你可以使用vim,但很多时候它是过度的。还有两件事要考虑: 如果你想查看非常大的文件,你将需要在尽可能快

笨办法学 Linux Bash:Shell、`.profile`、`.bashrc`、`.bash_history`

Bash:Shell、.profile、.bashrc、.bash_history。 当使用CLI(命令行界面)来使用Linux时,你正在与一个名为shell的程序进行交互。所有你输入的都传递给she

笨办法学 Linux 学习处理文件,`pwd`,`ls`,`cp`,`mv`,`rm`,`touch`

Bash:处理文件,pwd,ls,cp,mv,rm,touch 在Linux中,一切都是文件。但是什么是文件?现在完全可以说,它是一个包含一些信息的对象。它通常定义如下: 计算机文件是用于存储信息的

工具分享:Linux tree 命令安装和使用

说明tree命令是一个比较实用文件系统查看工具,如下图,可以阶梯式地罗列某个目录下的所有子目录:如何安装?RHEL/CentOS下:#yuminstalltree-yDebian/Ubuntu, Mi

【Linux 工具】服务器文件传输利器 lrzsz

场景  服务端开发人员经常会遇到的一个场景就是将本地的文件传到服务器上,或者把服务器上的文件下载到本地,那这个时候大家一般会用ftp服务,来完成这件事。但是如果服务器上并没有安装ftp服务的时候,这个

Linux系统——架构浅析

导语:掐指一算自己从研究生开始投入到Linux的海洋也有几年的时间,即便如此依然对其各种功能模块一知半解。无数次看了Linux内核的技术文章后一头雾水,为了更系统地更有方法的学Linux,特此记录。历

这些linux技巧大大提高你的工作效率

前言linux中的一些小技巧可以大大提高你的工作效率,本文就细数那些提高效率或者简单却有效的linux技巧。命令编辑及光标移动这里有很多快捷键可以帮我们修正自己的命令。接下来使用光标二字代替光标的位置

AWS vs K8s 是新时代的 Windows vs Linux?

作者:IanMiell是开源程序员、演讲师、作家和博客写手以前……如果你与我一样,年过四十,又在IT行业工作,恐怕还记得每个人使用Windows,一小群但越来越多的人在业余时间埋头编译Linux的年代

韩国政府:放弃Windows 7,转投Linux

对于政府和企业而言,2020年4月是一个非常值得关注的时间,因为在这个时间,微软将会停止对Windows7的支持。正是只有不足一年的时间,很多政府和企业再次与微软合作,不过其中的花销相当高。韩国政府面

Linux 中删除目录的多种方法

有几种不同的方法可以删除 Linux 系统中的目录。如果您使用桌面文件管理器(如Gnome的文件管理器或KDE的Dolphin),则可以使用管理器的图形用户界面删除文件和目录。但是,如果您正在使用无头