RosettaCodeData/Task/Active-object/Perl/active-object.pl

70 lines
1.2 KiB
Perl

#!/usr/bin/perl
use strict;
use 5.10.0;
package Integrator;
use threads;
use threads::shared;
sub new {
my $cls = shift;
my $obj = bless { t => 0,
sum => 0,
ref $cls ? %$cls : (),
stop => 0,
tid => 0,
func => shift,
}, ref $cls || $cls;
share($obj->{sum});
share($obj->{stop});
$obj->{tid} = async {
my $upd = 0.1; # update every 0.1 second
while (!$obj->{stop}) {
{
my $f = $obj->{func};
my $t = $obj->{t};
$obj->{sum} += ($f->($t) + $f->($t + $upd))* $upd/ 2;
$obj->{t} += $upd;
}
select(undef, undef, undef, $upd);
}
# say "stopping $obj";
};
$obj
}
sub output { shift->{sum} }
sub delete {
my $obj = shift;
$obj->{stop} = 1;
$obj->{tid}->join;
}
sub setinput {
# This is surprisingly difficult because of the perl sharing model.
# Func refs can't be shared, thus can't be replaced by another thread.
# Have to create a whole new object... there must be a better way.
my $obj = shift;
$obj->delete;
$obj->new(shift);
}
package main;
my $x = Integrator->new(sub { sin(atan2(1, 1) * 8 * .5 * shift) });
sleep(2);
say "sin after 2 seconds: ", $x->output;
$x = $x->setinput(sub {0});
select(undef, undef, undef, .5);
say "0 after .5 seconds: ", $x->output;
$x->delete;