【问题标题】:POE complains that POE::Kernel's run method was never called when I forkPOE 抱怨我 fork 时从未调用过 POE::Kernel 的 run 方法
【发布时间】:2010-12-31 17:03:41
【问题描述】:

这是我的代码:

 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 的运行方法没有被调用。该脚本确实进入了后台并像它应该的那样工作,这意味着内核确实正在运行。我只是想摆脱那个烦人的警告。

【问题讨论】:

    标签: perl fork poe


    【解决方案1】:

    你说得对。出现警告是因为 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
    

    虽然您的代码 sn-p 显示会话是在子进程中创建并运行的,但我怀疑会话是在之前或之后创建的。父进程不会在你的 sn-p 中退出,所以不知道之后执行到哪里?

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

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

    【讨论】:

    • 这为我解决了一个问题。我认为 POE::Component::Resolver 会在导入时自行设置 - 如果您分叉,POE 会抱怨并且子进程将无法正常工作。如果在子进程中调用 $poe_kernel->run ,解析器关闭,fork 正常工作。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • $poe_kernel 与 POE::Kernel 相同。 run() 只需要在所有会话启动后调用一次。只有当我在 fork()'d child 中执行此操作时才会出现警告。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-16
    • 2019-01-26
    • 2021-09-22
    相关资源
    最近更新 更多