Coro で Two-Phase Termination パターン

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 を参考に Coro で Two-Phase Termination パターンを実装。

Two-Phase Termination パターンは別スレッドに止まれと命令して、別スレッドに終了処理させる。終了処理が終ってスレッドが終了するのを待つ。


#!/usr/bin/perl
use strict;
use warnings;

package Countup;
use Coro;
use Coro::Timer;
use Error qw(:try);

sub new {
    my ( $class, %args ) = @_;
    $args{counter} = 0;
    $args{shutdown_requested} = 0;
    bless \%args, $class;
}

sub shutdown_request {
    my $self = shift;
    my $coro = shift;
    $self->{shutdown_requested} = 1;
    $coro->throw("Shutdown Request");
}

sub is_shutdown_requested {
    my $self = shift;
    return $self->{shutdown_requested};
}

sub start {
    my $self = shift;
    try {
        while (!$self->is_shutdown_requested()) {
            $self->do_work();
        }
    }
    catch Error with {
        my $e = shift;
        print qq{catch "}, $e->text, qq{"\n};
    }
    finally {
        $self->do_shutdown();
    };
}

sub do_work {
    my $self = shift;
    $self->{counter}++;
    print "do_work : counter = ", $self->{counter}, $/;
    Coro::Timer::sleep(1);
}

sub do_shutdown {
    my $self = shift;
    $self->{counter}++;
    print "do_shutdown\n";
}

package main;
use Coro;
use Coro::Timer;

print "main : BEGIN\n";
my $countup;
my $coro = async {
    $countup = Countup->new();
    $countup->start();
};

Coro::Timer::sleep(3);

print "main : shutdown_request\n";
$countup->shutdown_request($coro);
$coro->join();
print "main : END\n";

出力

$ perl -w TwoPhaseTermination.pl
main : BEGIN
do_work : counter = 1
do_work : counter = 2
do_work : counter = 3
main : shutdown_request
catch "Shutdown Request"
do_shutdown
main : END

pic ファイル

.PS

copy "sequence.pic";

boxwid = 1.3;

# Define the objects
object(M,":main");
placeholder_object(T);
step();

# Message sequences
active(M);
create_message(M,T,":countup");
message(M,T,"start");
active(T);
rmessage(T,M,"");

message(T,T,"is_shutdown_requested");
active(T);
step();
inactive(T);
comment(T,C,down 0.5 left 0.5,wid 0.75 ht 0.25 "false");

message(T,T,"do_work");
active(T);
step();
inactive(T);

message(T,T,"is_shutdown_requested");
active(T);
step();
inactive(T);
connect_to_comment(T,C);

message(T,T,"do_work");
active(T);
step();
inactive(T);

message(M,T,"shutdown_request");
rmessage(T,M,"");

message(M,T,"join");
comment(M,C,up 0.5 left 0.25,wid 1.25 ht 0.25 "waiting for finish");

message(T,T,"is_shutdown_requested");
active(T);
step();
inactive(T);
comment(T,C,down 0.5 left 0.5,wid 0.75 ht 0.25 "true");

message(T,T,"do_shutdown");
active(T);
step();
inactive(T);

rmessage(T,M,"");
delete(T);

complete(M);

.PE