You have not given enough information. It would be immensely helpful if
you could give a minimal example which does not do what you want, and
explain exactly what you would like it to do instead, you will have a
better chance of getting useful responses.
As it stands, trying to help you involves setting up a lot of
scaffolding based on guesswork which I doubt many people will be doing.
Sinan
Sure, more info is always helpful...
The sample below consists of two files:
mt_test.pl which is the main perl file, and
testmulti.pm which is the perl module.
I would like to find the best way to allow the subroutines in
testmulti.pm to access some shared variables made possible through
multithreading. If someone out there believes this isbad programming
practice, then please suggest the best way to get the info I'm looking
for in the script below.
The idea in this example is to run a counter in multiple threads. As
the counters run, I would like to have a shared variable incremented as
each counter thread executes it's iteration of the counter.
The code below is broken, in that I'm not sure how to get the
subroutines in testmulti.pm to access the shared variable from
mt_test.pl.
The tracker() subroutine needs to be able to check the shared variables
in order to report status. The join method only allows data to be
returned when the thread exits. However, I would like the tracker
process to be able to collect live data from the counter threads while
they are running. In reality, these threads will be running for minutes
or hours, and I would like to have the tracker process report data as
close to realtime as possible.
I have gotten this to run when all the subroutines are in the
mt_test.pl, but I would like to run the subroutines in a module for
repeated use among other perl programs.
When it runs in a single perl script it looks like this:
# ./mt_test.pl
Counter1 Counter4 Counter5 TOTAL
1 1
2 1 3
3 1 4
4 2 6
5 2 1 8
However, in the "modularized" state I only get this:
# ./mt_test.pl
Counter1 Counter4 Counter5 TOTAL
All Threads have closed, shutting down tracker
EXIT Values: 1: 0 2: 0 3: 0 Trk:
Attempt to free unreferenced scalar: SV 0x8c272bc, Perl interpreter:
0x8b75cf0 during global destruction.
Attempt to free unreferenced scalar: SV 0x8ba4f00, Perl interpreter:
0x8b13ed0 during global destruction.
Attempt to free unreferenced scalar: SV 0x8b431ac, Perl interpreter:
0x8ab1b58 during global destruction.
Attempt to free unreferenced scalar: SV 0x8adffa8, Perl interpreter:
0x89b3050 during global destruction.
<mt_test.pl>
#!/usr/bin/perl
# Threading requires use of the "threads" module
use threads;
# In order to use shared variables, you need to include the
"threads::shared" module
use threads::shared;
use testmulti qw(tracker counter);
## COUNTER EXAMPLE ##
# In this example we're going to start 3 threads of incrementing
counters
# each counter runs at a different time interval.
# The purpose of this example is to show how to use shared memory for
# constantly running threads
# Establish some shared variables for the counters
my %stats : shared; #This hash is used to track the stats of each
counter.
my $total : shared; #This string variable holds the total of all
counters and is writable via variable locking
my $end_test=9; #Here we define how many test intervals to run
# Let's run 3 counters of different sleep intervals
my @tests : shared = (1,2,5);
# Start the threads
# Here we are creating threads that will call the counter() subroutine.
# the second argument is the list of variables to pass to the
subroutine
# Syntax: $handle = threads->create(subroutine,list of args);
my $counter1 = threads->create("counter", "$tests[0],$end_test");
my $counter4 = threads->create("counter", $tests[1]);
my $counter5 = threads->create("counter", $tests[2]);
# Run status tracker in seperate thread
# We will use this thread to collect the data from the shared variables
# and print the results.
# "tracker" is the name of the subroutine to call
# "1" is the number of seconds to sleep in between checks
my $tracker1 = threads->create("tracker", "1,@tests");
# The join() method allows you to collect return data from the thread
when it closes
my $return1 = $counter1->join();
my $return4 = $counter4->join();
my $return5 = $counter5->join();
my $returnt = $tracker1->join();
print "EXIT Values: 1: $return1 2: $return4 3: $return5 Trk:
$returnt\n";
</mt_test.pl>
<testmulti.pm>
# Multithread test package
package testmulti;
use strict;
use base 'Exporter';
use vars qw(@ISA @EXPORT);
@ISA = ('Exporter');
@EXPORT = qw(&tracker &counter);
#use threads::shared;
#my %stats : shared; #This hash is used to track the stats of each
counter.
#my $total : shared; #This string variable holds the total of all
counters. We use this to show locking
# Subroutine that tracks the results of the running counters
sub tracker {
my ($interval, @tests) = @_;
# Take the count of the number of running processes and increase by
1 since it's 0 based
my $num_tests = $#tests;
$num_tests++;
#print column headers
print "Counter1 Counter4 Counter5 TOTAL\n" ;
# Start the while loop for this subroutine
while () {
# Pull the list of running threads and increment counter of
running threads
my (@running_threads) = threads->list();
my $num_threads = $#running_threads;
$num_threads++;
# Detect a thread is missing and alert
print "A Thread has shut down\n" if $num_threads < $num_tests;
# For the purposes of a clean shutdown, we want the tracker to
return to the main thread when it's done.
# It becomes done, when all of the other threads have shut down.
if ($num_threads == 1){
print "All Threads have closed, shutting down tracker\n";
return;
}
# Print counter result data, if there's anything to print
print
"\t$stats{$tests[0]}\t$stats{$tests[1]}\t$stats{$tests[2]}\t$total\n"
if $stats{$tests[0]};
sleep $interval;
}
}
#Simple subroutine for counting something
sub counter{
my ($interval, $end_test) = @_;
# This is an "internal counter" that will be used to generate a return
value
# I only use it here to simulate having some value to return.
my $int_ctr=0;
# Run the counter until we reach the max number of counter tests to
run, as defined by a global variable
while($total < $end_test){
print "\t\t\t\t\tCounter $interval reports the total as $total\n";
sleep $interval;
#lock($stats{$interval});
$stats{$interval}++;
# Lock the $total variable for writing. This causes other threads
to block while waiting for the lock to be released
# THe lock is released when the code context is exited at the end
of the BLOCK
lock($total);
$total++;
$int_ctr++;
}
# Return a known value so that we know what we're getting in the
join() method
return $int_ctr;
}
1;
</testmulti.pm>