Appropiate Coro/AnyEvent model?
Mark Lawrence
nomad at null.net
Sun Nov 17 21:08:12 CET 2013
Hi Andrew,
Thanks for the reply.
> You're on the right track, but it sounds like you're only waiting for
> success inside do_stuff(), but because success never happens, it gets
> stuck waiting forever.
... possibly, but my issue is not that my program is stopping while
waiting for input or some true condition. The program stops responding
to events and something somewhere (inside Coro?) attempts to use 100%
of the cpu.
> Seems that really you should be waiting for success OR error, and
> have some way to tell the difference. Here's one approach:
...
> sub do_stuff {
> ...
>
> $self->{interrupt} = rouse_cb;
> AE::io $self->{child_stdout}, 0, $self->{interrupt};
>
> rouse_wait $self->{interrupt};
> $self->{interrupt} = undef;
The last thing I want to be doing inside the do_stuff() subroutine is
waiting on possible errors. There is nothing event based about that
approach. Waiting on (normal) input (hence the use of Coro) is however
fine.
I have come up with better, tested example code which we can run and
compare results with, which should hopefully show the problem clearer.
This program simply echos any input received, and the coro should be
stopped when an interrupt (^C) is received.
package Client;
use strict;
use warnings;
use Coro;
use Coro::Handle;
sub new {
my $class = shift;
bless my $self = {}, $class;
$self->{sig} = AE::signal 'INT', sub {
warn 'got INT';
# Uncomment one of the following to test
# Coro::terminate; # spin/lockup
# $Coro::current->safe_cancel; # spin/lockup
# $Coro::current->cancel; # spin/lockup
# Coro::current->throw('stuff'); # kills program entirely
exit;
};
$self->{fh} = Coro::Handle->new_from_fh(*STDIN);
return $self;
}
sub do_stuff {
my $self = shift;
while ( my $line = $self->{fh}->readline ) {
print "Got: $line";
}
return;
}
package main;
use Coro;
my $coro = async {
my $client = Client->new;
$client->do_stuff;
};
$coro->join;
warn 'After join + terminate/cancel/throw';
Uncomment any of the terminate/cancel options in the signal handler,
and Coro decides that it doesn't want to behave nicely anymore.
Stopping the coroutine from *outside* the coro however works fine:
package Client;
use strict;
use warnings;
use Coro::Handle;
sub new {
my $class = shift;
bless my $self = {}, $class;
$self->{fh} = Coro::Handle->new_from_fh(*STDIN);
return $self;
}
sub do_stuff {
my $self = shift;
while ( my $line = $self->{fh}->readline ) {
print "Got: $line";
}
return;
}
package main;
use Coro;
use AnyEvent;
my $cv = AnyEvent->condvar;
my $coro = async {
my $client = Client->new;
$client->do_stuff;
$cv->send;
};
my $w = AE::signal 'INT', sub {
warn 'got INT';
$coro->safe_cancel;
$cv->send;
};
$cv->recv;
warn 'After join + terminate/cancel/throw';
After all of that I guess I can phrase my question better now: Can a
coro thread stop itself?
Possibly related to this whole issue is the question of why
Coro::Handle doesn't deal with errors the same way that
AnyEvent::Handle does. I had been hoping that Coro::Handle would have
an on_error => sub {} capability.
Mark.
--
Mark Lawrence
More information about the anyevent
mailing list