Linux / Perl - 当一个进程分叉时会发生什么?

Linux / Perl - 当一个进程分叉时会发生什么?

我读过有关 fork 的文章,据我所知,进程被克隆了,但是是哪个进程呢?脚本本身还是启动脚本的进程?

例如:

我在自己的机器上运行 rTorrent,当一个 torrent 完成时,我会针对它运行一个脚本。此脚本从网络获取数据,因此需要几秒钟才能完成。在此期间,我的 rtorrent 进程被冻结。因此,我使用以下命令创建了脚本分支

my $pid = fork();
if ($pid) == 0) { blah blah blah; exit 0; }

如果我从 CLI 运行此脚本,它会在后台运行,一秒钟内返回到 shell,正如我所期望的那样。但是,当我从 rTorrent 运行它时,它似乎比以前更慢了。那么到底分叉了什么?rtorrent 进程克隆了自身,我的脚本在其中运行,还是我的脚本克隆了自身?我希望这是有道理的。

答案1

UNIX环境高级编程作者:W. Richard Stevens(第 188 页):

8.3fork功能

仅有的Unix 内核创建新进程的方式是现有进程调用该fork函数。(这不适用于我们在上一节中提到的特殊进程 — swapper、init和 pagedaemon。这些进程是由内核在引导过程中专门创建的。)

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);
/* Returns: 0 in child, process ID of child in parent, -1 on error */

由此创建的新进程fork称为子进程。该函数被调用一次但返回两次。返回值的唯一区别是子进程的返回值为 0,而父进程的返回值为新子进程的进程 ID。将子进程的进程 ID 返回给父进程的原因是因为一个进程可以有多个子进程,因此没有函数允许进程获取其子进程的进程 ID。将fork0 返回给子进程的原因是因为一个进程只能有一个父进程,因此子进程始终可以调用getppid以获取其父进程的进程 ID。(进程 ID 0 始终由交换器使用,因此 0 不可能是子进程的进程 ID。)

子进程和父进程继续执行调用 之后的指令fork。子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和堆栈的副本。请注意,这是子进程的副本 — 父进程和子进程不共享这些内存部分。如果文本段是只读的,父进程和子进程通常共享该文本段(第 7.6 节)。

在 Linux 上,Perl 的fork操作员呼叫系统的fork并在失败时返回undef而不是 -1。

史蒂文斯给出了列表(第 192 页),列出了父进程与其分叉子进程之间的继承属性和差异:

除了打开的文件之外,子进程还可以继承父进程的许多其他属性:

  • 真实用户ID, 真实组ID, 有效用户ID, 有效组ID
  • 补充组 ID
  • 进程组ID
  • 会话 ID
  • 控制终端
  • 设置用户 ID 标志和设置组 ID 标志
  • 当前工作目录
  • 根目录
  • 文件模式创建掩码
  • 信号屏蔽和配置
  • 任何打开的文件描述符的 close-on-exec 标志
  • 环境
  • 连接的共享内存段
  • 资源限制

父母与孩子之间的区别是

  • 返回值来自fork
  • 进程 ID 不同
  • 两个进程有不同的父进程 ID——子进程的父进程 ID 就是父进程;父进程的父进程 ID 不变
  • 孩子的tms_utimetms_stimetms_cutime和值tms_ustime设置为 0
  • 父进程设置的文件锁不会被子进程继承
  • 为孩子清除待处理的警报
  • 子进程的待处理信号集设置为空集

相关内容