The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Padre::Task - Padre Background Task API

SYNOPSIS

Create a subclass of Padre::Task which implements your background task:

  package Padre::Task::Foo;
  
  use base 'Padre::Task';
  
  # This is run in the main thread before being handed
  # off to a worker (background) thread. The Wx GUI can be
  # polled for information here.
  # If you don't need it, just inherit the default no-op.
  sub prepare {
          my $self = shift;
          if ( condition_for_not_running_the_task ) {
                  return "BREAK";
          }
          
          return 1;
  }

  # This is run in a worker thread and make take a long-ish
  # time to finish. It must not touch the GUI, except through
  # Wx events. TODO: explain how this works
  sub run {
          my $self = shift;
          # Do something that takes a long time!
          return 1;
  }

  # This is run in the main thread after the task is done.
  # It can update the GUI and do cleanup.
  # You don't have to implement this if you don't need it.
  sub finish {
          my $self = shift;
          my $mainwindow = shift;
          # cleanup!
          return 1;
  }
  
  1;

From your code, you can then use this new background task class as follows. (new and schedule are inherited.)

  require Padre::Task::Foo;
  my $task = Padre::Task::Foo->new(some => 'data');
  $task->schedule(); # hand off to the task manager

As a special case, any (arbitrarily nested and complex) data structure you put into your object under the magic main_thread_only hash slot will not be passed to the worker thread but become available again when finish is called in the main thread. You can use this to pass references to GUI objects and similar things to the finish event handler since these must not be accessed from worker threads.

DESCRIPTION

This is the base class of all background operations in Padre. The SYNOPSIS explains the basic usage, but in a nutshell, you create a subclass, implement your own custom run method, create a new instance, and call schedule on it to run it in a worker thread. When the scheduler has a free worker thread for your task, the following steps happen:

The scheduler calls prepare on your object.
If your prepare method returns the string 'break', all further processing is stopped immediately.
The scheduler serializes your object with Storable.
Your object is handed to the worker thread.
The thread deserializes the task object and calls run() on it.
After run() is done, the thread serializes the object again and hands it back to the main thread.
In the main thread, the scheduler calls finish on your object with the Padre main window object as argument for cleanup.

During all this time, the state of your task object is retained! So anything you store in the task object while in the worker thread is still there when finish runs in the main thread. (Confer the CAVEATS section below!)

INSTANCE METHODS

schedule

Padre::Task implements the scheduling logic for your subclass. Simply call the schedule method to have your task processed by the task manager.

Calling this multiple times will submit multiple jobs.

new

Padre::Task provides a basic constructor for you to inherit. It simply stores all provided data in the internal hash reference.

run

This is the method that'll be called in the worker thread. You must implement this in your subclass.

You must not interact with the Wx GUI directly from the worker thread. You may use Wx thread events only. TODO: Experiment with this and document it.

prepare

In case you need to set up things in the main thread, you can implement a prepare method which will be called right before serialization for transfer to the assigned worker thread.

If prepare returns the string break (case insensitive), all further processing of the task will be stopped and neither run nor finish will be called. Any other return values are generally ignored.

You do not have to implement this method in the subclass.

finish

Quite likely, you need to actually use the results of your background task somehow. Since you cannot directly communicate with the Wx GUI from the worker thread, this method is called from the main thread after the task object has been transferred back to the main thread.

The first and only argument to finish is the Padre main window object.

You do not have to implement this method in the subclass.

post_event

This method allows you to easily post a Wx event to the main thread. First argument must be the event ID, second argument the data you want to pass to the event handler.

For a complete example, please check the code of Padre::Task::Example::WxEvent.

You can set up a new event ID in your Padre::Task subclass like this:

  our $FUN_EVENT_TYPE =  : shared = Wx::NewEventType();

Then you have to setup the event handler (for example in the prepare() method. This should happen in the main thread!

(TODO: Check the effect of declaring the same handler multiple times)

  Wx::Event::EVT_COMMAND(
      Padre->ide->wx->main_window,
      -1,
      $FUN_EVENT,
      \&update_gui_with_fun
  );
  
  sub update_gui_with_fun {
      my ($main, $event) = @_; @_=(); # hack to avoid "Scalars leaked"
      my $data = $event->GetData();
  }
  

After that, you can dispatch events of type $FUN_EVENT_TYPE by simply running:

  $self->post_event($FUN_EVENT_TYPE, $data);

NOTES AND CAVEATS

Since the task objects are transferred to the worker threads via Storable::freeze() / Storable::thaw(), you cannot put any data into the objects that cannot be serialized by Storable. To the best of my knowledge, that includes filehandles and code references.

SEE ALSO

The management of worker threads is implemented in the Padre::TaskManager class.

The transfer of the objects to and from the worker threads is implemented with Storable.

AUTHOR

Steffen Mueller smueller@cpan.org

COPYRIGHT AND LICENSE

Copyright 2008 Gabor Szabo.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5 itself.