分叉进程时会发生什么?

时间:2010-03-07 01:10:01

标签: linux perl unix posix fork

我读过关于fork的内容,根据我的理解,该过程是克隆的但是哪个过程?脚本本身或启动脚本的进程?

例如:

我正在我的机器上运行rTorrent,当一个torrent完成时,我有一个脚本运行它。此脚本从Web获取数据,因此需要几秒钟才能完成。在此期间,我的rtorrent进程被冻结。所以我使用以下

创建了脚本fork
my $pid = fork();
if ($pid == 0) { blah blah blah; exit 0; }

如果我从CLI运行这个脚本,它会在一秒钟内回到shell,而它在后台运行,就像我想要的那样。但是,当我从rTorrent运行时,它似乎比以前更慢。究竟是什么分叉了? rtorrent进程是否克隆了自己并且我的脚本在那里运行,或者我的脚本是否克隆了自己?我希望这是有道理的。

6 个答案:

答案 0 :(得分:6)

fork()函数返回TWICE!一旦进入父进程,就进入子进程一次。一般来说,两个进程在各方面都是IDENTICAL,就好像每个进程刚从fork()返回一样。唯一的区别是,在一个中,fork()的返回值是0,而在另一个中,它是非零(子进程的PID)。

因此,运行Perl脚本的任何进程(如果它是rTorrent中的嵌入式Perl解释器,那么rTorrent将是进程)将在fork()发生的那一点上重复。

答案 1 :(得分:4)

我相信通过查看rTorrent的来源我发现了这个问题。对于某些进程,它将在继续之前读取发送到stdout的所有输出。如果您的进程发生这种情况,rTorrent将阻塞,直到您关闭stdout进程。因为您正在分叉,所以您的子进程与父进程共享相同的标准输出。您的父进程将退出,但管道仍保持打开状态(因为您的子进程仍在运行)。如果你做了一个rTorrent,我敢打赌,在执行你的命令时,这个read()调用会被阻止。

尝试在fork()之前关闭/重定向perl脚本中的stdout。

答案 2 :(得分:3)

包含解释器分叉的整个过程。幸运的是,内存是写时复制的,所以它不需要复制所有进程内存以便fork。但是,诸如文件描述符之类的东西仍然是开放的。这允许子进程处理它们,但如果没有适当地关闭它们可能会导致问题。通常,fork()不应在嵌入式解释器中使用,除非在极端胁迫下。

答案 3 :(得分:2)

我的建议是“不要那样做”。

如果Perl解释器嵌入在rtorrent进程中,你几乎肯定会分叉整个过程,其效果最多可能是不明确的。无论语言如何,在嵌入式解释器中使用流程级别的东西通常是一个坏主意。

很有可能某种锁没有被正确释放,或者进程中的线程正在以非预期的和可能的竞争方式进行。

答案 4 :(得分:2)

要回答名义上的问题,因为您评论接受的答案未能这样做,fork会影响调用它的过程。在你的rTorrent产生一个Perl进程然后调用fork的例子中,Perl进程是重复的,因为它是调用fork的Perl进程。

在一般情况下,进程无法fork除了自身以外的任何进程。如果有可能告诉另一个任意进程本身fork,那将无法解决安全性和性能问题。

答案 5 :(得分:1)

当我们使用fork创建进程时,子进程将拥有地址空间的副本。因此,子进程也可以使用地址空间。它还可以访问由父进程打开的文件。我们可以拥有控制孩子。为了获得孩子的完整状态,我们可以使用等待。