首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何共享包含文件句柄的对象?

如何共享包含文件句柄的对象?
EN

Stack Overflow用户
提问于 2011-11-20 15:49:26
回答 3查看 1.5K关注 0票数 16

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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);

票数 6
EN

Stack Overflow用户

发布于 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的文件句柄就会被丢弃。

子项中发生的更改不会共享。

对于我的目的来说,这些都是可以接受的,每个进程只会创建几个这样的对象。

票数 1
EN

Stack Overflow用户

发布于 2011-11-22 15:41:58

话又说回来,如果对巨魔没有过敏反应,就可以使用https://metacpan.org/module/Coro

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8200159

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档