如何在子进程中禁用END块?

mob*_*mob 8 perl fork

我经常fork在也有END { ... }块的程序中使用:

...
END { &some_cleanup_code }
...
my $pid = fork();
if (defined($pid) && $pid==0) {
    &run_child_code;
    exit 0;
}
Run Code Online (Sandbox Code Playgroud)

子进程在END {}退出时执行块,但通常我不希望发生这种情况.有没有办法阻止子进程END在退出时调用块?除此之外,有没有办法让程序"知道"它是一个子进程,所以我可以说类似的东西

END { unless (i_am_a_child_process()) { &some_cleanup_code } }
Run Code Online (Sandbox Code Playgroud)

cjm*_*cjm 18

我认为没有办法阻止END块在分叉进程中运行,但这应该让你检测它:

my $original_pid; BEGIN { $original_pid = $$ }

... # Program goes here

END { do_cleanup() if $$ == $original_pid }
Run Code Online (Sandbox Code Playgroud)


eph*_*ent 15

perldoc -f退出

exit()函数并不总是立即退出.它首先调用任何已定义的END例程,但这些END例程本身可能不会中止退出.同样,在真正退出之前调用任何需要调用的对象析构函数.如果这是一个问题,您可以调用POSIX:_exit($status)以避免END和析构函数处理.有关详细信息,请参阅perlmod.

  • @cjm:迟到的'eval'END {使用POSIX"_exit"; POSIX :: _ exit(0)}'`将阻止其他`END`块运行,但不会阻止对象的'DESTROY`方法,并且也会捕获`die`. (3认同)
  • 唯一的问题是你必须抓住子进程可能退出的_every_方式.例如,如果它死了,并且你没有捕获它,那将运行END块. (2认同)

yst*_*sth 7

use B;
@{; eval { B::end_av->object_2svref } || [] } = ();
Run Code Online (Sandbox Code Playgroud)

我以为有一个Devel :: module也允许你这样做,但我现在找不到它.

当然,如果您使用可能正在使用END块的任意模块用于自己的目的,则无法安全地执行此操作...


(由OP编辑)您可以使用控件来控制END块B::end_av.作为概念验证:

END { print "This is the first end block.\n"; }
my $END_block_2_line = __LINE__ + 1;
END { print "This is the second end block.\n"; }
END { print "This is the third end block.\n" }

sub disable_specific_END_block {
  use B;
  my ($file, $line) = @_;
  eval {
    my @ENDs = B::end_av->ARRAY;
    for (my $i=$#ENDs; $i>=0; $i--) {
      my $cv = $ENDs[$i];
      if ($cv->START->file eq $file && $cv->START->line == $line) {
        splice @{B::end_av->object_2svref}, $i, 1;
      }
    }
  };
}

disable_specific_END_block(__FILE__, $END_block_2_line);
Run Code Online (Sandbox Code Playgroud)


$ perl endblocks.pl
This is the third end block.
This is the first end block.
Run Code Online (Sandbox Code Playgroud)

通常这样的东西对于我需要的东西来说太过分了,但是我可以看到一些这样的情况会派上用场.


tch*_*ist 6

从某种意义上讲,在fork儿童中避免这种情况的习惯方法是:

exec "true";
Run Code Online (Sandbox Code Playgroud)

或者,如果您发现太不值得信任,这些都可以工作,甚至可以使用use strict:

exec    $^X =>  -eexit;

exec ~~echo => ~~-echo;

exec ~~echo => !!-echo;
Run Code Online (Sandbox Code Playgroud)

和拟声词

exec reverse reverse echo => ~~-echo;
Run Code Online (Sandbox Code Playgroud)

Rebmemer-在Perl中,没有愚蠢的问题,但可能有愚蠢的答案......

$ perl -Mstrict '-leprint ucfirst lc reverse-Remember'
Run Code Online (Sandbox Code Playgroud)