我读过关于fork的内容,根据我的理解,该过程是克隆的但是哪个过程?脚本本身或启动脚本的进程?
例如:
我正在我的机器上运行rTorrent,当一个torrent完成时,我有一个脚本运行它。此脚本从Web获取数据,因此需要几秒钟才能完成。在此期间,我的rtorrent进程被冻结。所以我使用以下
创建了脚本forkmy $pid = fork();
if ($pid == 0) { blah blah blah; exit 0; }
如果我从CLI运行这个脚本,它会在一秒钟内回到shell,而它在后台运行,就像我想要的那样。但是,当我从rTorrent运行时,它似乎比以前更慢。究竟是什么分叉了? rtorrent进程是否克隆了自己并且我的脚本在那里运行,或者我的脚本是否克隆了自己?我希望这是有道理的。
答案 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创建进程时,子进程将拥有地址空间的副本。因此,子进程也可以使用地址空间。它还可以访问由父进程打开的文件。我们可以拥有控制孩子。为了获得孩子的完整状态,我们可以使用等待。