Perl线程不支持共享文件句柄。共享数据结构的所有元素都必须是共享的。如果需要共享一个包含文件句柄的对象,这就会出现问题。
{
package Foo;
use Mouse;
has fh =>
is => 'rw',
default => sub { \*STDOUT };
}
use threads;
use threads::shared;
my $obj = Foo->new;
$obj = shared_clone($obj); # error: "Unsupported ref type: GLOB"
print {$obj->fh} "Hello, world!\n";
文件句柄是否为“共享”并不重要,它只用于输出。也许有一个技巧,文件句柄存储在共享对象之外?
这个对象实际上包含在另一个共享对象中,该共享对象又位于另一个共享对象中,依此类推。最大的讽刺是,所讨论的对象本身从不使用线程,但如果用户使用线程,则必须在整个进程中保持协调。
can be seen here中的实际代码:这些对象用于配置格式化输出的位置。对象是必需的,因为output does not always go to a filehandle。
发布于 2011-11-20 16:16:23
目前我还不能访问线程化Perl,所以不能保证它能正常工作。
但一种有点简单的方法是使用一定级别的抽象,并将键/索引存储到对象中的全局文件句柄哈希/数组中,类似于以下内容:
my @filehandles = (); # Stores all the filehandles ### CHANGED
my $stdout; # Store the index into @filehandles, NOT filehandle.
# Should really be renamed "$stdout_id" instead.
sub stdout {
my $self = shift;
return $stdout if defined $stdout;
$stdout = scalar(@filehandles); ### CHANGED
my $stdout_fh = $self->dup_filehandle(\*STDOUT); ### CHANGED
push @filehandles, $stdout_fh; ### CHANGED
$self->autoflush($stdout_fh); ### CHANGED
$self->autoflush(\*STDOUT);
return $stdout;
}
sub safe_print {
my $self = shift;
my $fh_id = shift; ### CHANGED
my $fh = $filehandles[$fh_id]; ### CHANGED
local( $\, $, ) = ( undef, '' );
print $fh @_;
}
我有一种强烈的感觉,您需要以某种方式对I列表进行线程安全保护,因此可能需要一个共享索引计数器来代替$stdout = scalar(@filehandles);
发布于 2011-11-22 14:24:35
这是我最终得到的..。
package ThreadSafeFilehandle;
use Mouse;
use Mouse::Util::TypeConstraints;
my %Filehandle_Storage; # unshared storage of filehandles
my $Storage_Counter = 1; # a counter to use as a key
# This "type" exists to intercept incoming filehandles.
# The filehandle goes into %Filehandle_Storage and the
# object gets the key.
subtype 'FilehandleKey' =>
as 'Int';
coerce 'FilehandleKey' =>
from 'Defined',
via {
my $key = $Storage_Counter++;
$Filehandle_Storage{$key} = $_;
return $key;
};
has thread_safe_fh =>
is => 'rw',
isa => 'FilehandleKey',
coerce => 1,
;
# This converts the stored key back into a filehandle upon getting.
around thread_safe_fh => sub {
my $orig = shift;
my $self = shift;
if( @_ ) { # setting
return $self->$orig(@_);
}
else { # getting
my $key = $self->$orig;
return $Filehandle_Storage{$key};
}
};
1;
使用类型强制确保即使在对象构造函数中也可以进行从filehandle到key的转换。
它是有效的,但也有缺陷:
每个对象冗余地存储其文件句柄。如果一堆对象都存储相同的文件句柄,那么它们可能只存储一次。诀窍在于如何识别相同的文件句柄。fileno
或refaddr是选项。
删除对象时,文件句柄不会从%Filehandle_Storage中删除。我最初放了一个克隆方法来做这件事,但是由于对象克隆习惯用法是$clone = shared_clone($obj)
,所以一旦$obj超出范围,$ DESTROY
的文件句柄就会被丢弃。
子项中发生的更改不会共享。
对于我的目的来说,这些都是可以接受的,每个进程只会创建几个这样的对象。
发布于 2011-11-22 15:41:58
话又说回来,如果对巨魔没有过敏反应,就可以使用https://metacpan.org/module/Coro。
https://stackoverflow.com/questions/8200159
复制相似问题