0

我想从 cgi 调用中分叉一个后台进程。这样 httpd 调用立即返回,其余的东西继续运行

在我们迁移到新机器之前,这一直有效

............
## Close the http connection so that the remote client returns
close STDOUT;
close STDERR;
POSIX::setsid();
fork() && exit;
do_job();
.........

现在在新机器上,相同的代码永远不会执行 do_job() Perl,httpd 版本相同(有一个小的内核升级)

现在我将代码更改为

..........
open(STDOUT,">/dev/null");
open(STDERR,">/dev/null");
POSIX::setsid();
fork() && exit;
do_job();
.........

这有效,但我不知道为什么

4

2 回答 2

1

我不太确定为什么第一个代码会起作用。但是你应该总是把 setid 放在 fork() 之后。请让我知道在你这样做之后它是否不起作用。

每个进程组都在一个唯一的会话中。(当进程创建时,它成为其父会话的成员。)按照惯例,会话的会话 ID 等于会话的第一个成员的进程 ID,称为会话领导者。进程使用系统调用getsid() 查找其会话的ID。

一个新的会话由

pid = setsid();

仅当当前进程不是进程组负责人时才允许这样做。

让我解释一下为什么。假设您是进程组组长或会话组长,您必须了解进程组和会话 id 是从创建它们的进程的进程 id 初始化的(然后领导它们,即会话组长 pid == sid 和进程组长 pid == pgid)。此外,进程组不能在会话之间移动。

这意味着如果您是进程组组长,并且允许创建新会话,则 sid 和 pgid 将设置为您的 pid,从而使旧进程组中的其他进程处于奇怪的状态:他们的进程组组长突然与他们自己可能在不同的会话中。这是不允许的,因此内核返回了 EPERM。

现在如果你 fork() 一旦你既不是会话也不是进程组负责人,因此将你的 sid 和 pgid 设置为你的 pid 是安全的,因为在这样的组中没有其他进程。

以下链接可能会有所帮助:

会话和进程组

Linux 内核:进程

于 2013-01-28T08:57:06.730 回答
0

我建议您使用处理此类工作的外部队列。您可以使用一些 CPAN 模块来获得此功能,如Queue::DBI或其他模块,如Gearman

于 2013-01-28T08:29:28.287 回答