Part of this just will not work.

I've tried ripping out the variables to live in the global space
(shudder) and everything...

I just get:
Subthread: Processing queue item /Applications/Poser 7/Runtime/kuyg.pz2
ST: working: /Applications/Poser 7/Runtime/kuyg.pz2
thread failed to start: lock can only be used on shared values at
PolymorphLayout.pl line 825.

Line 825 is the one that says:
                    $wip = Wx::PlThreadEvent->new(-1, $qWorkEVT, $pct_done);

I stuck the bareblock on just because, it doesn't matter. I don't
know. I'm just shooting in the dark now.
Up in the top I have it clerarly saying (outside of the constructor
and everything):

our $qWorkEVT :shared;
our $pct_done :shared;
$qWorkEVT = Wx::NewEventType;
$pct_done = 0;


sub process_queue {
    my $self = shift;
    my $e = shift;
    @_ = ();

    $self->{qthr} = threads->create(
        sub {
   #         my $pct_done :shared;
            $pct_done = 0;
            #share($pct_done);

            while (my $q = (grep $_->{status} eq 'queued',
@{$self->{queue}})[0]) {
                my $wip;
                warn "Subthread: Processing queue item $q->{outputFile}\n";

                if (scalar(grep $_->{status} ne 'queued', @{$self->{queue}})) {
                    $pct_done = scalar @{$self->{queue}} /
(scalar(grep $_->{status} ne 'queued', @{$self->{queue}}) * 100);
                }
                else {
                    $pct_done = 0;
                }

                $q->{status} = 'working';
                warn "ST: working: $q->{outputFile}\n";
   #             warn is_shared($qWorkEVT) ? "\$qWorkEVT is shared\n"
: "\$qWorkEVT is not shared.\n";
   #             warn is_shared($pct_done) ? "\$pct_done is shared\n"
: "\$pct_done is not shared.\n";
                {
                    $wip = Wx::PlThreadEvent->new(-1, $qWorkEVT, $pct_done);
                }
                warn "ST: Past throwback\n";
                Wx::PostEvent($self, $wip);
                sleep 6;
                $q->{status} = 'done';

                if (scalar(grep $_->{status} ne 'queued', @{$self->{queue}})) {
                    $pct_done = scalar @{$self->{queue}} /
(scalar(grep $_->{status} ne 'queued', @{$self->{queue}}) * 100);
                }
                else {
                    $pct_done = 0;
                }

                {
                    $wip = Wx::PlThreadEvent->new(-1, $qWorkEVT, $pct_done);
                }
                Wx::PostEvent($self, $wip);
            }

            $pct_done = 100;
            my $qdone = new Wx::PlThreadEvent(-1, $qWorkEVT, $pct_done);
            Wx::PostEvent($self, $qdone);
        }
    );
}


2009/7/14 Dodger <[email protected]>:
> Hey all, especially Mattia,
>
> I'm working my way through threads in Wx and I'm looking into using
> threads to implement background queue processing. The user adds stuff
> to a queue, which is a part of the app object, and it processes a loop
> on the back end. Basically, I want them to be able to add to that
> queue while it's going, without having to pause it.
>
> I'm about to go to bed before delving into doing the real code, so I
> figured I should throw this up to see if I'm approaching things right,
> and see if there are any responses when I wake up.
>
> Basically, in simple form, I'm thinking this is the right approach,
> and I am about to try it. However, threads are tricky so even if it
> works, if someone sees this and screams NO THAT'S WRONG I need to
> listen. So, am I getting the approach right here?
>
> package Polymorph;
>
> use threads;
> use threads::shared;
> use Wx(':everything'); # I despise using 'qw' for one thing no matter
> how many things everywhere do it as an example
> use vars ('@ISA');
> @ISA = ('Wx::Frame');
>
> sub new {
>   �...@_[3, 4, 5, 6] = (Polymorph', [-1, -1], [760, 610],
> wxMINIMIZE_BOX|wxMAXIMIZE_BOX|wxSYSTEM_MENU|wxCAPTION|wxCLOSE_BOX);
>    my $self = shift->SUPER::new(@_);
>
>    $self->{params} = {};
>    $self->{queue} = &share([]);
>    $self->{qWorkEVT} = Wx::NewEventType;
>    &share($self->{qWorkEVT});
>
>    Wx::Event::EVT_COMMAND($self, -1, $self->{qWorkEVT}, \&wip_queue_process);
>
>    # all the other GUI setup stuff goes here, including buttons which
> trigger the events for subs below
> }
>
> sub add_to_queue { # add current to queue button pressed
>    my $self = shift;
>    my $e = shift;
>
>    $self->{queue} ||= &share([]);
>
>    my $q = &share({});
>    for my $k (keys %{$self->{params}}) {
>        $q->{$k} = $self->{params}->{$k};
>    }
>    $q->{status} = 'queued';
>    push @{$self->{queue}}, $q;
> }
>
> sub process_queue { # start processing queue button pressed
>    my $self = shift;
>    my $e = shift;
>   �...@_ = (); # do I need to do this if I shift in the vars? PBP is
> full of crap on this one, IMO. I always shift in $self, and $e is easy
> to do it with too.
>
>    $self->{qthr} = threads->create(
>        sub {
>            my $pct_done : shared = 0;
>            &share($pct_done);
>
>            while (my $q = (grep $_->{status} eq 'queued',
> @{$self->{queue}})[0]) {
>                # not a for loop, in case the queue changes in the meanwhile
>                warn "processing queue item $q->{outputFile}\n";
> #warning while developing, since most of this will be quiet instead
>                # do stuff to process the batch entry
>                $q->{status} = 'done';
>                $pct_done = scalar @{$self->{queue}} / (scalar(grep
> $_->{status} ne 'queued', @{$self->{queue}}) * 100);
>                my $wip = new Wx::PlThreadEvent(-1, $self->{qWorkEVT},
> $pct_done);
>                Wx::PostEvent($self, $wip);
>            }
>
>            $pct_done = 100;
>            my $qdone = new Wx::PlThreadEvent(-1, $self->{qWorkEVT}, 
> $pct_done);
>            Wx::PostEvent($self, $qdone);
>        }
>    );
> }
>
> sub wip_queue_process {
>    my $self = shift;
>    my $e = shift;
>
>    my $pct_done = $e->GetData;
>    # Update a gauge, maybe, or something... print to the status bar. Whatever.
>
>    if ($pct_done == 100) {
>        $self->finish_queue_process($e);
>    }
> }
>
> sub finish_queue_process {
>    my $self = shift;
>    my $e = shift;
>    warn "queue processing done.\n";
>    $self->{qthr}->join; # the examples don't show this anywhere, but
> it's bad to not do this, right? Zombies, brain-eating, all that...
>                               # And isn't this the perfect time to catch it?
> }
>
>
> package main;
>
> unless (caller) {
>    local *Wx::App::OnInit = sub {1};
>
>    my $app = Wx::App->new();
>    my $window = Polymorph->new();
>
>    $app->SetTopWindow($window);
>    $window->Show(1);
>    $app->MainLoop();
> }
>
>
>
> BTW!
> On a side note, I noticed something funny looking in the docs.
>
> In the Wx threading pod, it says:
>
> "Sending events from worker threads
>
> Wx::PlThreadEvent can be used to communicate between worker and GUI
> threads. The event can carry a shared value between threads.
>
>  my $DONE_EVENT : shared = Wx::NewEventType;
>
>  sub work {
>      # ... do some stuff
>      my $progress = new Wx::PlThreadEvent( -1, $DONE_EVENT, $progress );
>      Wx::PostEvent( $frame, $progress );
>
>      # ... do stuff, create a shared $result value
>      my $end = new Wx::PlThreadEvent( -1, $DONE_EVENT, $result );
>      Wx::PostEvent( $frame, $end );
>  }
> The target of the event can be any Wx::EvtHandler"
>
> However, there seems to be something wrong in that. Mainly in that
> there's a '$progress' variable declared in a my, but being dependant
> on already being defined in the same scope.
>
> I'm thinking something like this is what was meant, instead:
>
> "
> Sending events from worker threads
>
> Wx::PlThreadEvent can be used to communicate between worker and GUI
> threads. The event can carry a shared value between threads.
>
>  my $DONE_EVENT : shared = Wx::NewEventType;
>
>  sub work {
>      # ... do some stuff, generating a shared $progress variable
>      my $progress_so_far = Wx::PlThreadEvent->new(-1, $DONE_EVENT, $progress);
>      Wx::PostEvent( $frame, $progress_so_far );
>
>      # ... do stuff, create a shared $result value
>      my $end = Wx::PlThreadEvent->new( -1, $DONE_EVENT, $result );
>      Wx::PostEvent( $frame, $end );
>  }
> The target of the event can be any Wx::EvtHandler
> "
>
> That avoids saying my $progress = new Wx::PlThreadEvent(-1,
> $DONE_EVENT, $progress);
> and thus avoids using $progress to define my $progress, because I'm
> pretty sure that's not right. I mean, unless you are defining
> $progress elsewhere.
>
> --
> Dodger
>



-- 
Dodger

Reply via email to