使用线程进入Perl面向对象的包

时间:2014-01-14 15:28:15

标签: multithreading perl oop

我有这个测试脚本:

use threads;

start();

sub start {
  my $A = threads->create(\&A);
  my $B = threads->create(\&B);
  sleep;
}

sub A {
  while (1) {
    print "A\n";
    sleep(1);
  }
}

sub B {
  while (1) {
    print "B\n";
    sleep(1);
  }
}

此输出将是(每秒一次,永远):

A
B

我正在尝试使用面向对象的包:

package Test;
use threads;

sub new { my ($class) = @_;
  my $self = {
    A => undef,
    B => undef
  };
  bless $self, $class;
  return $self;
}

sub start { my ($self) = @_;
  $self->{A} = threads->create(\&{$self->A});
  $self->{B} = threads->create(\&{$self->B});
  sleep;
}

sub A { my ($self) = @_;
  while (1) {
    print "A\n";
    sleep(1);
  }
}

sub B { my ($self) = @_;
  while (1) {
    print "B\n";
    sleep(1);
  }
}

1;

然后:

use Test;

my $test = Test->new();

$test->start();

此输出将是(每秒一次,永远):

A

似乎代码卡在第一个线程上。我很难理解Perl中线程背后的逻辑。如何从面向对象的包中的第一个脚本复制相同的行为?

2 个答案:

答案 0 :(得分:1)

$self->A是一个永不返回的方法调用,因此\&{$self->A}也永远不会返回,您永远无法定义$self->{B}

一种方法是

$self->{A} = threads->create( sub { $self->A } );
$self->{B} = threads->create( sub { $self->B } );

表达式sub { $self->A }定义一个(匿名)子例程并将其传递给threads::create方法,但不调用子例程,允许程序继续。

答案 1 :(得分:0)

这是一个更有趣的测试脚本。

您应该通过在匿名子例程中关闭实例来调用对象实例上的方法。

我不知道您希望通过threads->create{\&{$self->A}};

实现什么目标

在调用create之前,调用$self->A必须返回一个值。但是,它的设计永远不会回归。但是,那么,你应该在你的create调用中使用大括号。所以,至少可以说这很令人困惑。

另外,请不要试图通过牺牲代码的可读性来保存行。

package Test;
use strict;
use warnings;
use threads;

sub new {
    my $class = shift;
    return bless { A => undef, B => undef } => $class;
}

sub start {
    my $self = shift;
    $self->{$_} = threads->create(sub { $self->$_ }) for qw(A B);
    $self->{$_}->join for qw(A B);
    return;
}

sub A {
    my $i = 'A';
    while (10 > time - $^T) {
        print "$i\n";
        $i++;
        sleep 1;
    }
}

sub B {
    my $i = '0';
    while (10 > time - $^T) {
        print "$i\n";
        $i++;
        sleep 1;
    }
}

package Main;

use strict;
use warnings;

my $test = Test->new;
$test->start;