NAME

Tk::Threaded - Apartment threaded wrapper for Perl/Tk

SYNOPSIS

        #
        #       define an apartment threaded Model object
        #
        package ButtonHandler;

        use Thread::Apartment::Server;
        use base qw(Thread::Apartment::Server);

        use strict;
        use warnings;

        sub new {
                my ($class, $tac, $mw, $img) = @_;

                my $self = bless {_mw => $mw, _img => $img }, $class;
                $self->set_client($tac);
        #
        #       register ourselves with Tk::Threaded
        #
                $mw->register(
                        -initialize => sub { $self->install(); },
                        -finalize => sub { $self->finalize(); });
                return $self;
        }
        #
        #       called before Tk::Threaded enters MainLoop
        #
        sub install {
                my $self = shift;
                my ($mw, $img) = ($self->{_mw}, $self->{_img});

                my $btn = $mw->Button(
                        -image => $img,
                        -command => sub { print "Button press!!!\n"; });
                $btn->pack();
        }

        sub finalize {
                print "We're all done!\n";
        }
        #
        #       usual TAS stuff...
        #
        sub get_simplex_methods {
                return { install => 1 };
        }
        #
        #       now build the app
        #
        use Thread::Apartment;
        #
        #       create a pool before installing Tk
        #
        Thread::Apartment->create_pool(AptPoolSize => 4);
        #
        #       then load Tk::Threaded with any widget classes it needs
        #
        require Tk::Threaded qw(Tk::Button Tk::Photo);
        import Tk::Threaded MainLoop;
        #
        # create MainWindow as usual
        #
        my $mw = MainWindow->new();
        #
        #       use it as usual
        #
        my $img = $mw->Photo(-data => components_gif(), -format => 'gif');
        #
        #       install another T::A object into the thread pool,
        #       passing it the Tk objects it needs
        #
        my $handler = Thread::Apartment->new(
                AptClass => 'ButtonHandler',
                AptParams => [ $mw, $img ]
        );
        #
        #       all set, so let her rip!
        #
        Tk::Threaded->MainLoop();

DESCRIPTION

Tk::Threaded provides an apartment threading wrapper for Perl/Tk. In general, Tk is not threads-friendly:

Thread::Apartment provides all the neccesary plumbing to wrap Tk in the root thread, and expose all its methods via a client proxy, so that other Thread::Apartment objects can blissfully use Tk - even concurrently - without needing to implement their own threads-capable request queueing or closure proxying.

METHODS

Tk::Threaded exposes nearly all the standard Tk methods, including the widget factory methods, as well as supporting passing and invoking closure arguments. Note that the objects returned from widget factory methods are actually proxy Thread::Apartment::Client objects, but behaviorally, applications shouldn't really be able to tell the difference from the "real thing" (with a few minor exceptions).

Application Notes and Restrictions

require'ing Widget Packages

Applications which use widgets outside of the "standard" widget set should specify them in a list in the require Tk::Threaded statement, e.g.,

        require Tk::Threaded qw(Tk::Button Tk::Photo Tk::DynaTabFrame);

Note that the specified Tk packages are loaded into the Tk::Threaded::Server apartment thread, not the local thread in which the Tk::Threaded object is created.

Also, best practice is to create an Thread::Apartment thread pool for all the apartment threaded objects, including Tk::Threaded, prior to require'ing any other packages, in order to minimize the amount of context cloned into all the apartment threads.

Finally, be advised that it is unneccesary to use/require Tk widget packages into other apartment threads that create/use widgets. Instead, simply supply the full list of packages in the require Tk::Threaded list, or call the $mw->require(@package_list) method which will pull in the needed packages within the Tk::Threaded::Server thread.

Application Architectures

The following options are available when applying Tk::Threaded:

Simple: Tk::Threaded as View Component

For simple applications with minimal GUI interaction requirements, using Tk::Threaded alone as the View component may be sufficient. In such architectures, the application

That's all thats required to implement simple threaded GUI's with Tk::Threaded.

However, there are limitations:

Advanced: Merging View components with Tk::Threaded

For more advanced applications with complex GUI interaction requirements, Tk::Threaded provides the CoHabitant() factory method. This method permits View objects to be created and executed within Tk::Threaded's apartment thread, subject to the same thread governor as Tk::Threaded. Such objects avoid the overhead of proxied method calls, and support a more complete set of Tk functionality, without the more complicated coding required to create a complete Tk MegaWidget.

To install a View component into Tk::Threaded:

By creating higher level View objects built on top of Tk, exposing high-level interfaces for Model objects, and installing the View objects within the Tk::Threaded apartment, the low-level GUI operations are executed entirely within the Tk::Threaded apartment, without the overhead of threads::shared data exchanges, and usage restrictions imposed by the simple proxied approach.

Best Practices

Avoid using after(), repeat(), fileevent()

While Tk::Threaded does support these async event dispatchers, they're really not needed for properly threaded architectures. With Tk::Threaded, there's no longer any need to interleave your timer or I/O events with Tk's control loop, or to even to worry about long running operations (unless, of course, you need some higher priority feedback from the GUI).

Instead, just write simple objects which block on I/O objects, or implement your own timer Thread::Apartment object, and let Tk::Threaded just handle the GUI operations.

PREREQUISITES

Perl 5.8.4 or higher
Perl/Tk 804.027
Thread::Apartment 0.60 or higher

CHANGE HISTORY

Release 0.10

TO DO

Solve the tied variable interface issue

Currently, several Tk widgets permit variable references to be used to communicate to the GUI (e.g., -textvariable, -variable configuration parameters). These interfaces rely on ties, which cannot be supported by threads::shared variables...which would be required to reference the tied variables from outside the Tk apartment thread. Some solution based on a Thread::Sociable extension to provide "trigger" variables may be possible.

Convert Tk widgets demo

The best way to prove Tk::Threaded's capability, and surface any issue, would be to convert the entire widgets demo...but thats a lot of code, and ideally would be restructured to uses a threaded architecture. Any volunteers?

SEE ALSO

Perl/Tk

Thread::Apartment

Thread::Queue::Queueable,

Thread::Resource::RWLock,

threads

threads::shared

perlthrtut

AUTHOR & COPYRIGHT

Copyright(C) 2005, 2006, Dean Arnold, Presicient Corp., USA

Licensed under the Academic Free License version 2.1, as specified in the License.txt file included in this software package, or at OpenSource.org http://www.opensource.org/licenses/afl-2.1.php.