Вот что я завел ...
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;
Использование приведения типов гарантирует, что перевод из файлового дескриптора в ключ происходит даже в конструкторе объектов.
Работает, но есть недостатки:
Каждый объект сохраняет свой дескриптор файла с избыточностью. Если все объекты хранят один и тот же файловый дескриптор, они, вероятно, могут просто сохранить его один раз. Хитрость заключается в том, как идентифицировать один и тот же файловый дескриптор. fileno
или refaddr - это варианты.
Файловый дескриптор не удаляется из% Filehandle_Storage при удалении объекта. Первоначально я использовал для этого метод DESTROY
, но так как идиома клонирования объекта - это $clone = shared_clone($obj)
, дескриптор файла клона $ удаляется, когда $ obj выходит из области видимости.
Изменения, которые происходят у детей, не передаются.
Это все приемлемо для моих целей, которые будут создавать только несколько таких объектов на процесс.