1

这是我的代码:

 if ($DAEMON) {
                my $pid = fork();
                if (not defined $pid) {
                                        print "Unable to start daemon.\n";
                                        exit(1);
                                      }
                elsif ($pid == 0) {
                                   open STDOUT, '>', '/dev/null';
                                   open STDERR, '>', '/dev/null';
                                   _create_sessions($self, $settings);
                                   $poe_kernel->run;
                                  }
                else { print "Script forked to background with PID $pid\n"; }
              }
 else {
        _create_sessions($self, $settings);
        $poe_kernel->run;
      }

当 $DAEMON = 1 时,它抱怨 POE::Kernel 的 run() 方法从未被调用,但正如您在上面的代码中看到的那样,我已经这样做了。该脚本在守护程序模式下工作得非常好,但我无法摆脱该警告或理解它为什么这么说。我还尝试调用 $poe_kernel->has_forked() ,但这也没有什么不同。

我没主意了。有什么建议么?

更新添加:也许我不够清楚。下面的代码创建会话并运行内核。

_create_sessions($self, $settings);
$poe_kernel->run;

它工作得很好。只有当相同的代码在一个分叉的孩子中运行时,我才能将脚本发送到后台,它说 POE::Kernel 的运行方法没有被调用。该脚本确实进入了后台并像它应该的那样工作,这意味着内核确实正在运行。我只是想摆脱那个烦人的警告。

4

2 回答 2

2

是的。出现警告是因为 POE::Session 实例是在父进程中创建的,但它们没有得到运行的机会。

% perl -wle 'use POE; POE::Session->create(inline_states=>{_start => sub {}})'
40023: Sessions were started, but POE::Kernel's run() method was never
40023: called to execute them.  This usually happens because an error
40023: occurred before POE::Kernel->run() could be called.  Please fix
40023: any errors above this notice, and be sure that POE::Kernel->run()
40023: is called.  See documentation for POE::Kernel's run() method for
40023: another way to disable this warning.

在上面的示例中,40023 是检测到问题的进程 ID。

这类似于 Perl 关于退出活动线程的警告:

% perl -wle 'use threads; threads->create(sub { sleep 3600 }); '
Perl exited with active threads:
  1 running and unjoined
  0 finished and unjoined
  0 running and detached

虽然您的代码片段显示会话是在子进程中创建和运行的,但我怀疑会话是在之前或之后创建的。父进程不会在您的代码段中退出,因此不知道之后执行的位置?

您还应该在子进程中调用 POE::Kernel->has_forked()。我不知道您的代码片段中是否发生了这种情况。

正确的解决方案是在守护进程时将所有会话实例化移动到子进程中。一个可行的解决方法是在使用 POE::Kernel 之后和实际创建任何会话之前调用 POE::Kernel->run()。run() 将立即返回,因为不存在会话,但调用满足您被警告的条件。这是一种说“是的,是的,但我知道我在做什么”的方式。

于 2011-01-01T08:05:53.903 回答
1

从文档中, POE::Kernel 的 run 通常被称为类方法;$poe_kernel 是什么?

在某个地方,您似乎正在开始一个会话,但最终没有调用 POE::Kernel->run();

更新:由于您看到的消息是带有警告的输出,并且您正在丢弃孩子的 STDERR,我猜是父母发出警告。 您正在做的事情(在您没有显示加载 POE 并设置 $poe_kernel 的代码中?)实际上是在创建会话,显然是无意的。

尝试将您的代码简化为一个简短但可运行的示例,您将自己找到问题或让其他人帮助您找到问题。

于 2010-12-31T17:57:43.350 回答