Threads and OO Question

E

Edward Wildgoose

I have a peculiar problem with threads on Perl 5.8 (activestate on Win32)

My sample code is below, however, the problem is basically that if I run
this under the debugger then if "works" as expected. Works in this case
defined as some output goes to stdout.

However, if I simply run the program from the command line, then I only get
output from the thread running "MyPackage->start"... There is no output
from the main thread. Any ideas why (does it happen to anyone else? Linux?)
Is this to do with one of the threads grabbing stdout and the other not
being able to access it?

Secondly is this the "right" way to do thread programming? The "problem" I
am trying to solve is to have the main start thread showing a GUI interface,
where the MyPackage class is then a worker class which goes off and does
something. Then the GUI will periodically access the properties of
"MyPackage" to determine state and progress (and update the GUI). FWIW,
there is a deliberate attempt to keep the two processes seperate hence not
relying on the any abilities the GUI toolkit might provide to do background
processing.

Thanks

Ed W


use threads;
use threads::shared;

use strict;

package MyPackage;

my $counter : shared;
$counter = 0;

sub new {
my $class = shift;
my $this = {COUNTER => 0};
threads::shared::share($this->{COUNTER});

$counter = 0;

return bless($this, $class);
}

sub start {
my $this = shift;

while (1) {
$counter += 1;
$this->{COUNTER} += 1;
sleep 1;
print STDOUT "In Counter: $counter \r\n";
}
}

sub getCounter {
my $this = shift;
return $this->{COUNTER};
# return $counter;
}


package main;

sub MainLoop {
my $a;
my $a = MyPackage->new();

my $thr = threads->new(sub{$a->start();});
sleep 1;

while (1) {
my $count = $a->getCounter();
print STDOUT $count;
sleep 1;
}

my @ReturnData = $thr->join;
print "Thread returned @ReturnData";
}

MainLoop();
 
B

Bill

Edward Wildgoose said:
I have a peculiar problem with threads on Perl 5.8 (activestate on Win32)

It's not threads, it's io buffering

Add


$| = 1;

to the top of the program.
 
E

Edward Wildgoose

I have a peculiar problem with threads on Perl 5.8 (activestate on
Win32)
It's not threads, it's io buffering

Add

$| = 1;

Bah! Yep, fixes everything!

Can anyone point me to any other references on the new perl threads. I have
read the man pages, and perlthrtut. I'm basically confused as to how to
share variables between threads when the variable to be shared is a class.
I'm aware this is fairly limited at the moment, but advice on how to make
something like the below share variables correctly would be appreciated:

Thanks,

Ed W


<scribble mode on>

package main;

my $worker = Worker->new();
my $thr = threads->new(sub{$worker->start();});
while (1) {
my $stats = $worker->CheckStats();
useful_function( $stats->Do_Something_With_Object() );
}

##############################
package Worker;

sub new {
my $class;
return bless( {Stats => MyStats->new(), $class}
}

sub start { do_something(); }

sub CheckStats {
my $this;
return $this->{Stats};
}


####################
package MyStats;

sub new {
my $class;
my $self = { bytes_in => 0,
bytes_out => 0};

return bless($self, $class);
}

sub increment { etc }

....etc...
 
E

Edward Wildgoose

Can anyone point me to any other references on the new perl threads. I
have
read the man pages, and perlthrtut. I'm basically confused as to how to
share variables between threads when the variable to be shared is a class.
I'm aware this is fairly limited at the moment, but advice on how to make
something like the below share variables correctly would be appreciated:



Partly answering my own question, it seems I can do the following:

package MyStats;
use threads::shared;

sub new {
my $class = shift;
my $this = { bytes_in => 0,
bytes_out => 0};
share($this);

return bless($this, $class);
}

sub increment {
my $this = shift;
$this->{bytes_in} += shift;
$this->{bytes_out} += shift;
}

From reading the documentation it wasn't clear that this was valid, or even
correct (ie sharing the whole $this variable). Presumably this breaks if
anything in the $this is either a) not a scalar, or b) not itself shared?

Is there a more in-depth tutorial on this anywhere? It's kind of slow going
having to write all these experimental bits of code to test stuff out
first... (yeah, yeah, thread safe programming isn't supposed to be easy. I
know, I know!)

Thanks all

Ed W
 
B

Bill

Edward Wildgoose said:
read the man pages, and perlthrtut. I'm basically confused as to how to
share variables between threads when the variable to be shared is a class.


<scribble mode on>

package main;

my $worker = Worker->new();
my $thr = threads->new(sub{$worker->start();});
while (1) {
my $stats = $worker->CheckStats();
useful_function( $stats->Do_Something_With_Object() );
}

##############################
package Worker;

sub new {
my $class;
return bless( {Stats => MyStats->new(), $class}
}

Good question, I think. Maybe Arthur Bergman knows the answer.


Do you have to share the class, or could you create a hash containing
the data you want shared and share the hash?

I say this because the docs on threads::shared (have you looked at
threads::shared?) says that

" bless is not supported on shared references. In the current version,
bless will only bless the thread local reference and the blessing will
not propagate to the other threads. This is expected to be implemented
in a future version of Perl."
 
E

Edward Wildgoose

Good question, I think. Maybe Arthur Bergman knows the answer.

Sorry for my ignorance. Who is this person? Aha, google turns up "who" he
is, but does he run a web page of useful info? (Anyone?)
Do you have to share the class, or could you create a hash containing
the data you want shared and share the hash?

Nope, I just learned to use classes on Perl and I went wild...

However, this then brings us full circle back to the problem. In the main
thread how do I talk back to the worker thread in order to ask it to
populate the shared hash? (I want to avoid nasty IPC stuff since I already
wrote a socket communicator to the other process and I'm trying this method
to avoid all that junk!) Because it seems to me that if the main thread
calls some function, say, "getSomeInternalState", then this function cannot
access the non-shared objects in order to populate the shared hash....

So if the worker thread is using shared hashes to proxy data back to the
main thread then I might as well not bother with my Statistics encapsulation
class at all since it's just a duplication...

(Did that make any sense?)

Yes, I can use semaphores to communicate to the worker process and get it to
populate the shared hash, but so much nicer if I could just share the
internal state object in the first place!
I say this because the docs on threads::shared (have you looked at
threads::shared?) says that

" bless is not supported on shared references. In the current version,
bless will only bless the thread local reference and the blessing will
not propagate to the other threads. This is expected to be implemented
in a future version of Perl."

Yeah, agree. However, see my other post because that code works on
Activestate 5.8 (whatever the latest is as of today. build 806?)

I have included the whole test script below:

....Should this work? Does it work under linux...? What the heck is going
on...? Help!

Thanks all

Ed W


use threads;

use strict;

package MyStats;
use threads::shared;

sub new {
my $class = shift;
my $this = { bytes_in => 0,
bytes_out => 0};
share($this);

return bless($this, $class);
}

sub increment {
my $this = shift;
$this->{bytes_in} += shift;
$this->{bytes_out} += shift;
}


package MyPackage;
use threads::shared;

my $counter : shared;

sub new {
my $class = shift;
my $this = {STATS => MyStats->new()};
share($this->{STATS});

return bless($this, $class);
}

sub start {
my $this = shift;

while (1) {
$counter += 1;
$this->{STATS}->increment(1,2);
sleep 1;
print STDOUT "In Counter: $counter \r\n";
}
}

sub getCounter {
my $this = shift;
return $this->{STATS};
# return $counter;
}


package main;
use threads::shared;

sub MainLoop {
$| = 1;

my $a;
my $a = MyPackage->new();

my $thr = threads->new(sub{$a->start();});
sleep 1;

while (1) {
my $count = $a->getCounter();
print STDOUT $count;
sleep 1;
}

my @ReturnData = $thr->join;
print "Thread returned @ReturnData";
}

MainLoop();
 
B

Bill

Edward Wildgoose said:
Sorry for my ignorance. Who is this person? Aha, google turns up "who" he
is, but does he run a web page of useful info? (Anyone?)
Oh, he wrote the threads routines in 5.8, I think...
However, this then brings us full circle back to the problem. In the main
thread how do I talk back to the worker thread in order to ask it to
populate the shared hash? (I want to avoid IPC stuff since I already

Well, if what you have works, I guess it's okay, but watch out for
race conditions.

Maybe one safe way is to create a flattened scalar representation of
the object--kind of like when you want to save an object to disk--and
pass that scalar via Thread::Semaphore?

However I've never done this, so I'm out of ideas.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top