在IPC :: ShareLite对象

时间:2019-03-26 05:56:54

标签: perl fork ipc

我有一个Perl程序,该程序分叉子流程并处理其中的N个项目,之后我需要将这些处理后的项目返回给主流程。

IPC::ShareLite从多个可用的IPC选项返回处理过的项目到主进程,这似乎是最简单的一个,但是我不确定它是否支持在一个共享库中存储多个项目。

这里是程序的摘录,但不起作用:

use IPC::ShareLite;

# create shared object in main process
my $share = new IPC::ShareLite(
    -key     => 1234,
    -create  => 'yes',
    -destroy => 'yes'
) or die $!;

# fork subprocesses, process and store N items in shared object
$share->store($member);

# After subprocesses finish, fetch items in main process
my $members_size = scalar @$members_ref;
@$members_ref = ();
while ($members_size > 0) {
    my $member = $share->fetch();
    push @$members_ref, $member;
    $members_size--;
}

以上代码失败,并在my $member = $share->fetch();上出现了相当模糊的错误:

  

IPC :: ShareLite fetch()错误:...处的参数无效

是否可以按预期使用IPC :: ShareLite对象,或者它只能容纳一项?

1 个答案:

答案 0 :(得分:2)

您正在使用fork创建一个子级,并且该子级获得$share对象的副本。当子项退出时,$share对象的子项副本将被销毁,这会导致基础系统资源被销毁,因为您使用了-destroy => 'yes'

通常,您要在执行分叉后 创建带有析构函数的对象。

但是在创建IPC :: ShareLite对象时,通常希望保留键以让系统为您选择键,但是您需要在创建派生之前进行操作。

解决方法

在子级中执行以下操作:

$share->destroy(0);

更好的解决方案

由于模块的正常使用模式涉及创建子进程继承的对象,因此模块应处理这种情况。

为此,您应该让模块的维护者更换模块,以便仅在当前PID与创建$share的PID相同的情况下才进行销毁。

sub _initialize {
  ...
  $self->{pid} = $$;   # ADD
  ...
}

sub DESTROY {
  my $self = shift;

  #destroy_share( $self->{share}, $self->{destroy} )                           # REMOVE
  destroy_share( $self->{share}, $self->{pid} == $$ ? $self->{destroy} : 0 )   # ADD
   if $self->{share};
}