原标题:你知道,当你在 Linux 上启动一个进程时会发生什么嘛?

本文是关于 fork 和 exec 是如何在 Unix 上工作的。你或许已经知道,也有人还不知道。几年前当我了解到这些时,我惊叹不已。

我们要做的是启动一个进程。我们已经在博客上讨论了很多关于系统调用的问题,每当你启动一个进程或者打开一个文件,这都是一个系统调用。所以你可能会认为有这样的系统调用:

start_process(["ls","-l","my_cool_directory"])

这是一个合理的想法,显然这是它在 DOS 或 Windows 中的工作原理。我想说的是,这并不是 Linux 上的工作原理。但是,我查阅了文档,确实有一个 posix_spawn 的系统调用基本上是这样做的,不过这不在本文的讨论范围内。

fork 和 exec

Linux 上的 posix_spawn 是通过两个系统调用实现的,分别是 fork 和 exec(实际上是 execve),这些都是人们常常使用的。尽管在 OS X 上,人们使用 posix_spawn,而 fork 和 exec 是不提倡的,但我们将讨论的是 Linux。

Linux 中的每个进程都存在于“进程树”中。你可以通过运行 pstree 命令查看进程树。树的根是 init,进程号是 1。每个进程(init 除外)都有一个父进程,一个进程都可以有很多子进程。

所以,假设我要启动一个名为 ls 的进程来列出一个目录。我是不是只要发起一个进程 ls 就好了呢?不是的。

我要做的是,创建一个子进程,这个子进程是我(me)本身的一个克隆,然后这个子进程的“脑子”被吃掉了,变成 ls。

开始是这样的:

my parent

|- me

然后运行 fork(),生成一个子进程,是我(me)自己的一份克隆:

my parent

|- me

|-- cloneof me

然后我让该子进程运行 exec("ls"),变成这样:

my parent

|- me

|-- ls

当 ls 命令结束后,我几乎又变回了我自己:

my parent

|- me

|-- ls(zombie)

在这时 ls 其实是一个僵尸进程。这意味着它已经死了,但它还在等我,以防我需要检查它的返回值(使用 wait 系统调用)。一旦我获得了它的返回值,我将再次恢复独自一人的状态。

my parent

|- me

fork 和 exec 的代码实现

如果你要编写一个 shell,这是你必须做的一个练习(这是一个非常有趣和有启发性的项目。Kamal 在 Github 上有一个很棒的研讨会:https://github.com/kamalmarhubi/shell-workshop)。

事实证明,有了 C 或 Python 的技能,你可以在几个小时内编写一个非常简单的 shell,像 bash 一样。(至少如果你旁边能有个人多少懂一点,如果没有的话用时会久一点。)我已经完成啦,真的很棒。

这就是 fork 和 exec 在程序中的实现。我写了一段 C 的伪代码。请记住,fork 也可能会失败哦。

intpid = fork();

// 我要分身啦

// “我”是谁呢?可能是子进程也可能是父进程

if(pid == 0){

// 我现在是子进程

// “ls” 吃掉了我脑子,然后变成一个完全不一样的进程

exec(["ls"])

}elseif(pid == -1){

// 天啊,fork 失败了,简直是灾难!

}else{

// 我是父进程耶

// 继续做一个酷酷的美男子吧

// 需要的话,我可以等待子进程结束

}

上文提到的“脑子被吃掉”是什么意思呢?

进程有很多属性:

打开的文件(包括打开的网络连接)

环境变量

信号处理程序(在程序上运行 Ctrl + C 时会发生什么?)

内存(你的“地址空间”)

寄存器

可执行文件(/proc/$pid/exe)

cgroups 和命名空间(与 Linux 容器相关)

当前的工作目录

运行程序的用户

其他我还没想到的

当你运行 execve 并让另一个程序吃掉你的脑子的时候,实际上几乎所有东西都是相同的! 你们有相同的环境变量、信号处理程序和打开的文件等等。

唯一改变的是,内存、寄存器以及正在运行的程序,这可是件大事。

为何 fork 并非那么耗费资源(写入时复制)

你可能会问:“如果我有一个使用了 2GB 内存的进程,这是否意味着每次我启动一个子进程,所有 2 GB 的内存都要被复制一次?这听起来要耗费很多资源!”

事实上,Linux 为 fork() 调用实现了写时复制copy on write,对于新进程的 2GB 内存来说,就像是“看看旧的进程就好了,是一样的!”。然后,当如果任一进程试图写入内存,此时系统才真正地复制一个内存的副本给该进程。如果两个进程的内存是相同的,就不需要复制了。

为什么你需要知道这么多

你可能会说,好吧,这些细节听起来很厉害,但为什么这么重要?关于信号处理程序或环境变量的细节会被继承吗?这对我的日常编程有什么实际影响呢?

有可能哦!比如说,在 Kamal 的博客上有一个很有意思的 bug。它讨论了 Python 如何使信号处理程序忽略了 SIGPIPE。也就是说,如果你从 Python 里运行一个程序,默认情况下它会忽略 SIGPIPE!这意味着,程序从 Python 脚本和从 shell 启动的表现会有所不同。在这种情况下,它会造成一个奇怪的问题。

所以,你的程序的环境(环境变量、信号处理程序等)可能很重要,都是从父进程继承来的。知道这些,在调试时是很有用的。返回搜狐,查看更多

责任编辑:

linux启动一个进程吗,你知道,当你在 Linux 上启动一个进程时会发生什么嘛?相关推荐

  1. 无法在web服务器上启动调试 web服务器未能找到,无法在Web服务器上启动调试。未将项目配置为进行调试...

    无法在Web服务器上启动调试.未将项目配置为进行调试 更新时间:2006年10月06日 00:00:00   作者: 第一种:如果你使用的是WinXP或者Win2kPro版的系统,你不会出现这个问题, ...

  2. linux启动一个进程吗,当你在Linux上启动一个进程时会发生什么?

    本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时,我惊叹不已. 我们要做的是启动一个进程.我们已经在博客上讨论了很多关于系统调用 ...

  3. linux如何启动一个进程而不阻塞,当你在 Linux 上启动一个进程时会发生什么? | Linux 中国...

    原标题:当你在 Linux 上启动一个进程时会发生什么? | Linux 中国 本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时 ...

  4. 多个客户端如何同时连接到服务器上的一个端口(例如80)? [重复]

    本文翻译自:How do multiple clients connect simultaneously to one port, say 80, on a server? [duplicate] T ...

  5. 计算机从网络上启动,如何设置计算机以从网络驱动器启动

    未考虑任何特定计算机. Not taking into account any specific computers. * 如何设置计算机以从网络驱动器启动? * 如何设置网络驱动器以允许自己启动. ...

  6. 用Canvas在SurfaceView上绘制一个雷达扫描动画

    用Canvas在SurfaceView上绘制一个雷达扫描动画 目录 用Canvas在SurfaceView上绘制一个雷达扫描动画 目录 为什么选择SurfaceView 准备工作 构建MySurfac ...

  7. 进程异常行为-访问恶意下载源 解决方案_不要忽略服务器上的异常进程

    在之前的文章中,我们看到了ADAudit Plus的用户行为分析(UBA)功能如何使管理员能够监视用户登录活动以识别受感染的帐户.ADAudit Plus中的UBA还可以帮助您跟踪成员服务器上的任何异 ...

  8. 在canvas(画布)上绘制一个矩形盒子并使用按键移动这个盒子

    思路 1.在画布上创建一个2d画笔,并用这个画笔在画布上绘制一个矩形. 2.设置一个边界判断使这个盒子不能移出画布之外,只能在画布中移动. 注意: 不能直接在style中设置canvas的大小 直接设 ...

  9. java 取字符串最后一个字符串_关于java:如何获取字符串的最后一个字符?

    如何获取字符串的最后一个字符? public class Main { public static void main(String[] args) { String s ="test st ...

最新文章

  1. json-lib把XML转化为json
  2. Android NDK开发之旅(2):一篇文章搞定Android Studio中使用CMake进行NDK/JNI开发
  3. 鸿蒙开发-新建Ability与使用image-animator实现图帧动画
  4. jQuery 表格自动增加
  5. [Java基础]Stream流的收集操作
  6. Selenium自动化测试-3.元素定位(3)
  7. 使用 Python 全栈打造淘宝客微信机器人(上)
  8. [云原生专题-26]:K8S - Kubernetes(K8S)Master集群构建与安装过程详细解读 - master节点的添加
  9. python梨视频爬虫下载,反反爬
  10. 拉肚子差评回复模板_女子吃外卖烧烤后拉肚子给差评,老板电话骂人后还说“欧耶”...
  11. IntelliJ IDEA|热部署
  12. C# 中的MessageBox 弹出提示框(消息框)的用法
  13. vue循环渲染不同图片
  14. 基于Rplidar二维雷达使用Hector_SLAM算法在ROS中建图
  15. SIMATIC S7-1200以及SIMATICS G120组态
  16. 【学习笔记1】C++除号“/”的使用
  17. 用不同的域名访问同一个空间上面不同的网站
  18. Sharepoint Workflow 获取中文栏的问题
  19. 谈谈标准,规范的问题
  20. java版丁丁历险记_【原版PDF漫画书】丁丁历险记The Adventures Of Tintin

热门文章

  1. 什么情况下PMP可自学?
  2. Geometric Distortion Correction 畸变矫正
  3. GEOSGeom_createLinearRing_r returned a NULL pointer该如何解决
  4. java基于springboot+Vue+nodejs的高校运动会报名管理系统 element
  5. 深度学习理论篇之----前世、今生、未来
  6. 树莓派(5):CSI摄像头 vs USB摄像头
  7. [新版新概念英语1-4册全部视频和课本]
  8. /backend_agg.py:238: RuntimeWarning: Glyph 26085 missing from current font.
  9. python之excel读写报表统计入门
  10. 【verilog学习23】HDLBits:Circuits_Sequential Logic_Finite State Machines