Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 当一个进程被分叉时会发生什么?_Linux_Perl_Unix_Posix_Fork - Fatal编程技术网

Linux 当一个进程被分叉时会发生什么?

Linux 当一个进程被分叉时会发生什么?,linux,perl,unix,posix,fork,Linux,Perl,Unix,Posix,Fork,我读过关于fork的书,据我所知,这个过程是克隆的,但是哪个过程呢?脚本本身还是启动脚本的进程 例如: 我正在我的机器上运行rTorrent,当一个torrent完成时,我会对它运行一个脚本。此脚本从web获取数据,因此需要几秒钟才能完成。在此期间,我的RTORENT进程被冻结。因此,我使用以下代码创建了脚本fork my $pid = fork(); if ($pid == 0) { blah blah blah; exit 0; } 如果从CLI运行此脚本,它会在后台运行时在一秒钟内返回s

我读过关于fork的书,据我所知,这个过程是克隆的,但是哪个过程呢?脚本本身还是启动脚本的进程

例如:

我正在我的机器上运行rTorrent,当一个torrent完成时,我会对它运行一个脚本。此脚本从web获取数据,因此需要几秒钟才能完成。在此期间,我的RTORENT进程被冻结。因此,我使用以下代码创建了脚本fork

my $pid = fork();
if ($pid == 0) { blah blah blah; exit 0; }
如果从CLI运行此脚本,它会在后台运行时在一秒钟内返回shell,这与我的预期完全一致。然而,当我从RtoCurrent运行它时,它似乎比以前还要慢。那么到底是什么分叉的呢?rtorrent进程是否克隆了自身并在其中运行了我的脚本,还是我的脚本克隆了自身?我希望这是有意义的。

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


因此,运行Perl脚本的任何进程(如果它是rTorrent中的嵌入式Perl解释器,那么rTorrent就是该进程)都会在
fork()
发生时被复制。

包含解释器fork的整个进程。幸运的是,内存是写时拷贝的,所以它不需要为了fork而拷贝所有进程内存。然而,诸如文件描述符之类的东西仍然是开放的。这允许子进程处理它们,但如果它们没有正确关闭,则可能会导致问题。一般来说,
fork()
不应该在嵌入式解释器中使用,除非是在极端胁迫下使用。

我的建议是“不要这样做”

如果Perl解释器嵌入到rtorrent进程中,那么几乎可以肯定您已经分叉了整个rtorrent进程,其效果最多可能定义不清。在嵌入式解释器中处理进程级的东西通常是一个坏主意,而不考虑语言


很有可能某些类型的锁没有被正确释放,或者进程中的线程以非预期的、可能相互竞争的方式运行。

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


尝试在
fork()之前关闭/重定向perl脚本中的stdout,以回答名义问题,因为您评论说接受的答案无法这样做,
fork
会影响调用它的过程。在您的示例中,rTorrent生成一个Perl进程,然后调用
fork
,这是重复的Perl进程,因为它是调用
fork
的Perl进程


在一般情况下,一个进程除了自身之外,没有办法将任何进程分支到
fork
。如果有可能让另一个任意进程自行执行
fork
,这将带来无尽的安全和性能问题。

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

请先发布一个有效的perl代码段。尝试在strace中运行rTorrent,看看脚本运行时它阻塞了什么。这可能会提供线索。我在想它可能一直在等待孙子进程,但似乎使用传统的系统调用实际上不可能实现行为。@jdizzle-可能是因为这个问题没有多大意义,因为
有人
不理解这个进程,也不理解他们的想法。解释一些事实可能会有所帮助:)@viraptor-我觉得有人对fork()的用法有足够的了解。问题其实是关于RtoCurrent的实现。问题是“哪一个被克隆了”,答案是“无论
fork()
运行在哪个进程中”(再加上一些关于
fork()
如何工作的额外解释,这将有助于理解为什么会发生这种情况)Meh。在最终用户的机器上用perl编写fork()并不是世界末日。我同意经常使用可能是不好的做法(因为这是一个瓶颈的成熟点)。如果这是一个不好的做法,是否有其他方法来防止阻塞?实际链接到perl解释器有多普遍?system()调用这类调用不是更实用(也更安全)吗?在多线程程序中调用
fork()
的确会带来麻烦。但是,如果您限制在子进程中发生的事情,那就没那么糟糕了。例如,不调用任何需要获取用户模式锁的内容。但是下列
fork()
dup2()
close()
execve()
等的典型用法应该是安全的。@jdizzle:针对外部解释器(Perl或其他解释器)的链接非常常见,但对于这个程序是否是这样的问题还不完全清楚。不过,重读一遍,你可能是对的,system()正在被使用。它不是嵌入式解释器。我让它启动一个外部脚本,所以它可以是perl,python,等等