fork和exec如何工作?


17

我没有太多的经验,只是试图参与到流程中,它们如何从用户级别解释为硬件。

因此,当从外壳启动命令时fork(),它将继承该命令的子进程并将exec()该子进程加载到内存中并执行。

  1. 如果子流程包含父流程(原始流程)的所有属性,那么该子流程有什么需求?原始进程也可能已加载到内存中。
  2. forkexec概念适用于UNIX中的所有可执行程序吗?是否也喜欢用于shell脚本或仅用于命令?它也适用于shell内置命令吗?
  3. 如果我将执行命令/脚本,何时使用复制概念?

抱歉一次问很多问题,但是当我想到任何命令执行时,所有这些问题立刻浮现在脑海。


我不会说这是重复的,但是我认为您的一些问题在这里得到了回答:unix.stackexchange.com/questions/136637/…以及在该问题顶部链接的其他答案。
goldilocks

Answers:


22

因此,当从外壳中触发命令时,fork()会继承它的子进程,而exec()会将子进程加载到内存中并执行。

不完全的。 fork()克隆当前进程,创建一个相同的子进程。 exec()将新程序加载到当前进程中,以替换现有程序。

我的qs是:

如果子进程包含父进程(原始进程)的所有属性,那么该子进程有什么需求?原始进程也可能已加载到内存中。

这是因为父进程还不想终止。它希望新流程能够启动并在继续执行的同时做一些事情。

这个fork和exec的概念适用于UNIX中的所有可执行程序吗?还是像shell脚本一样,或者仅像命令一样?它也适用于shell内置命令吗?

对于外部命令,shell会执行一个操作,fork()以便命令在新进程中运行。内置程序仅由外壳程序直接运行。另一个值得注意的命令是exec,它exec()无需先通知外壳即可将其告知外部程序fork()。这意味着外壳本身已被新程序替换,因此不再存在该程序在退出时返回的程序。如果你说exec true,然后/bin/true将取代你的shell,并立即退出,留下没有在你的终端上运行了,那么它将会关闭。

如果我要执行命令/脚本,何时使用写时复制概念?

回到石器时代,fork()实际上不得不将调用过程中的所有内存复制到新过程中。写时复制是一种优化,其中建立了页表,以便两个进程开始共享所有相同的内存,并且仅在需要时才复制两个进程写入的页面。


4
“对于几乎每个命令,外壳程序都会执行fork(),以便该命令在新进程中运行。如果该命令是内置命令,则子级不需要执行单独的程序。” 好的答案,但是这部分应该编辑。运行内置程序时,shell不分叉。它直接在活动的shell进程中运行它们。这是内置函数喜欢cdread可能起作用的唯一方法。缺少分叉也使内置函数比外部命令快得多。
约翰·库格曼

6
  1. 对于某些程序,子进程执行一件事(从串行端口读取,写入终端),而父进程继续执行其他事情(从终端读取,写入串行端口)。另一个经典示例是子进程对正在进行的任何长期计算进行检查。通常,子进程会进行一些设置,例如更改目录,重置信号处理程序或重置文件描述符,然后调用execve()以使用不同的代码覆盖自身。
  2. fork()并且exec()确实适用于所有可执行文件-实际上,与argc和argv一起使用,管道,fork和exec是Unix与其他操作系统的区别。fork()存在一些专业化或通用化,例如BSD vfork(),Plan 9 rfork()和Linux clone(),但是原理保持不变。
  3. “写时复制”并没有真正显示给用户,它更多是一种优化创建子流程及其执行过程的技术。调用堆栈和堆(分配malloc()有的内存,甚至是静态或全局作用域变量)可能是“写入时复制”。当子进程使用fork()调用时,内核会将子进程设置为与父进程具有与堆和堆栈完全相同的内存页面。如果硬件(内存管理单元)检测到堆或堆栈的写入,则内核将获得新的物理内存页,将父页面复制到新页面中,并将该新页面映射到子进程的堆栈或堆中。这构成了一种优化,因为内核花在建立页面映射上的时间少于为子进程完全复制堆栈和堆所花费的时间。

感谢布鲁斯的回答。但是,您在这里说的很多话让我头疼。我对这些东西不了解。.我将尽力使您提到的这些功能正常工作。非常感谢..!!
2015年

4
如果子流程包含父流程(原始流程)的所有属性,那么该子流程有什么需求?原始进程也可能已加载到内存中。

通过查看最早的Unix实现,可以很好地说明这个问题,该实现必须在严格的内存约束下工作,并且一次在内存/地址空间中只有一个执行进程。

多任务是通过将一个进程换出到磁盘并换入另一个进程来实现的。

现在,fork系统调用几乎是相同的:它将一个进程换出到磁盘上,但是没有换入另一个进程,而是给内存中的副本提供了另一个进程ID并返回给它。exec毕竟,这是决定该过程是否恰好进入另一个可执行文件的适当时机。

fork+ exec因此实际上并没有在产卵时产生明显的开销:无论如何,您都必须将进程换出到磁盘上,并且无论如何,您都必须将旧的进程映像放在可用的内存位置。

随着可用内存和内存管理单元数量的增加以及内存中多个进程的增加,最初可以忽略的Fork成本在某些架构上变得有些麻烦:因此vfork诞生了。


2

为了使这一点尽可能容易理解,我将使用一个类比。让我们烤馅饼!

我们拿起食谱书,开始阅读,然后定居在草莓大黄派(我最喜欢的)上,上面有手工制作的外壳。除了鸡蛋和水果,我们几乎需要的所有东西都在厨房里,但是由于我们住在农场,而且水果是时令的,所以这不是问题。问题是烤箱坏了,没有足够的时间做每一件事。有一个以上的人不是很好吗?

fork()进行救援。现在有两个人。我们俩都去厨房开始制作馅饼皮。哎呀 因此,我们看一下叉子的收益。我得到的数字很多,他为零,所以我去厨房,而他去鸡舍和花园。当我走过烤箱时,我再次fork(),看看返回值:bummer我得到了零。当我凝视着破损的烤箱时,他继续吃面粉。我打开门,不亮,我关上门。有人知道如何修理烤箱吗?

exec()进行救援。我伸手去拿工具带上的电压表,灯泡可以诊断出来,所以我检查电源,确实是断路器跳闸了,很容易修理。当我走到断路器面板时,我看到一个同伴正在采摘大黄。!我喜欢巧克力丝派。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.