我有一个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对象,或者它只能容纳一项?
答案 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};
}