# $Id: Threaded.pm,v 1.4 2004/10/16 21:13:28 jfontain Exp $


package Threaded; # sample/template for a non-blocking Perl module using threads
use threads;
use Thread::Queue;
use strict;
use warnings;

BEGIN {
    our $VERSION = qw($Revision: 1.4 $)[1];
}

our $in = Thread::Queue->new();                 # data generated from the thread
our $out = Thread::Queue->new();                        # data fed to the thread

sub work() {                 # collect and possibly process data inside a thread
    while (my $value = $in->dequeue()) {
        # simulate processing or potentially blocking operations
#       for (my $i = 0; $i < $value; $i++) {}     # processing (use large value)
        sleep(1 + int(rand($value)));                              # or blocking
        $out->enqueue(rand(100));                       # simulate gathered data
        yield('updated');  # give control back to the core which calls updated()
        # Note: this is required as the parent Perl interpreter is no longer
        # running at this time, and thus needs to be awaken by the application
        # core, which is always running.
        # Note: yield(), along with the after(), flashMessage(), pushMessage(),
        # popMessage() and traceMessage() subroutines are defined by the core in
        # the module namespace and therefore should be seen as reserved
        # subroutines, not to be redefined in the module (this file for the
        # Threaded module).
    }
}

our %data;
our @data;
our $asynchronous;

$data{updates} = 0;
$data{columns}[0] = {label => '', type => 'ascii', message => ''};      # hidden
$data{columns}[1] = {label => 'data', type => 'integer', message => 'value'};
$data{pollTimes} = [5, 1, 2, 10, 20, 30, 60, 120, 300];
$data{views} = [{indices => [1], sort => {1 => 'increasing'}}];
$data{persistent} = 1;
$data{switches} = {'-a' => 0, '--asynchronous' => 0};
$data[0][0] = '';
$data{helpText} = `cat Threaded.htm`;                 # load HTML formatted help

sub initialize(%) {
    my %option = @_;
    $asynchronous = (($option{'-a'} || $option{'--asynchronous'}));
    threads->new(\&work);       # create thread blocked waiting on queue for now
    if ($asynchronous) {
        $data{pollTimes} = [-2];             # update every 2 seconds on average
        $in->enqueue(3);                                   # start thread action
    }
}

our $busy;                        # whether the worker thread is busy processing

# note: the updated() subroutine is mandatory in threaded modules
sub updated() {  # possibly process data from the thread and trigger core update
    $data[0][1] = $out->dequeue();
    $data{updates}++;
    $busy = 0;                   # ready for more data collection and processing
    if ($asynchronous) {
        $in->enqueue(3);                                   # start thread action
    }
}

sub update() {
    if ($busy) {return};
    $busy = 1;
    $in->enqueue(3);                                       # start thread action
}

1;
