Daniel Rychlik <> wrote:
> I greatly appreciate the response from everyone regarding my threads.
> After 2 days of research I don't know if what Im trying to do is even
> possible but I've started down this road and with a project deadline
> its difficult to just start over with another language so I am
> looking to exploit threads to fullest capacity.
>
> Some of you have asked for code examples.
>
> One of issues that I am having is when the thread enters into
> getAvailableResource routine its not seeing that the
> $Resources{'WAN1'}->{INUSE} = 1; has been made unavailable. The idea
> is for the next thread to pick up the next unavailable resource. I
> tried to sleep(1) between thread creation, and also used
> threads::shared share(%Resources); which also failed.
You are not sharing %Resources correctly. See comments below.
>
> I am new to threads in PERL. Ive had great success with JAVA threads.
> This program is a bit of beast with all the things that it has to do
> before getting to the end result.
>
> This code will eventually be turned into a win32::service but only
> after I get it debugged and working correctly.
The same applies to using threads, i.e. get it working without using
threads first. Do you even need to use threads?
>
> I greatly appreciate everyones time in offering me advice in this
> situation.
>
> Thanks,
> Dan J. Rychlik
> IT Projects Engineer
>
> Sample code::
>
> #! c:\perl\bin\perl.exe
>
> use strict;
> use DBI;
> use threads;
> use threads::shared;
> use File::Path;
> use Win32::EventLog;
> use Win32::FileOp;
> use Win32::OLE;
> use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); use LWP::Simple;
>
> our (@sitePushData,$dbh);
>
> # List of directories to create upon install...
> my @Directories = ('c:\\DJ\\SITE_UPDATE\\LOG_DATA\\',
> 'c:\\DJ\\SITE_UPDATE\\QUEUE\\',
> 'c:\\DJ\\SITE_UPDATE\\SPOOL\\',
> 'c:\\DJ\\SITE_UPDATE\\COMPLETE\\',
> 'c:\\DJ\\BIN\\'
> );
>
> # Runtime Database for SITE ID Tracking our %RunTimeKey;
>
> # Runtime Resource handling
> our %Resources;
my %Resources : shared;
>
> # WAN Resources
> $Resources{'WAN1'} = {'DRIVE' => 'O:', 'INUSE' => 0};
See 'perldoc perlthrtut', "This places restrictions on what may be
assigned to shared array and hash elements: only simple values or
references to shared variables are allowed", so this should probably be
(unnecessary quotes removed) ...
$Resources{WAN1} = shared {DRIVE => 'O:', INUSE => 0};
> $Resources{'WAN2'} = {'DRIVE' => 'P:', 'INUSE' => 0};
> $Resources{'WAN3'} = {'DRIVE' => 'Q:', 'INUSE' => 0};
> $Resources{'WAN4'} = {'DRIVE' => 'R:', 'INUSE' => 0};
> $Resources{'WAN5'} = {'DRIVE' => 'S:', 'INUSE' => 0};
> $Resources{'WAN6'} = {'DRIVE' => 'T:', 'INUSE' => 0};
>
> # MODEM Resources
> $Resources{'POLL1'} = {'DRIVE' => 'U:', 'INUSE' => 0};
> $Resources{'POLL2'} = {'DRIVE' => 'V:', 'INUSE' => 0};
> $Resources{'POLL3'} = {'DRIVE' => 'W:', 'INUSE' => 0};
> $Resources{'POLL4'} = {'DRIVE' => 'X:', 'INUSE' => 0};
> $Resources{'POLL5'} = {'DRIVE' => 'Y:', 'INUSE' => 0};
> $Resources{'POLL6'} = {'DRIVE' => 'Z:', 'INUSE' => 0};
>
> share(%Resources);
>
> my ($file,$thread);
>
> while (1) {
>
> eval { mkpath([EMAIL PROTECTED], 1, 0777) };
> if ($@) {
> print "Could not create: $@";
> }
Does this really need to be repeated every time round the loop?
>
> opendir (QUEUE, $Directories[1]) or die "Unable to open $!\n";
>
> while (defined ($file = readdir (QUEUE)) ) {
>
> if ($file =~ m/^\d{5}/) {
>
> prepPackage($file);
> }
> }
>
> closedir(QUEUE);
>
> foreach my $rec (keys %RunTimeKey) {
>
> $thread = threads->create("getAvailableResource","$rec");
> $thread->detach();
It would be better (IMHO) to create a small number of threads, possibly
one per resource, at the start and pass $rec via a Thread::Queue, it is
only a scalar after all, than repeatedly creating threads.
Also, see 'perldoc -q quoting'.
>
> sleep(1);
>
> }
>
> print "All Quiet: Waiting for files\n";
> sleep (300);
>
> }
>
>
>
>
>
#-----------------------------------------------------------------------
> -----
> # Routine that handles the assignment of resources so that
> multitasking is # made useful
>
#-----------------------------------------------------------------------
> -----
> sub getAvailableResource {
>
> my ($siteId) = @_;
>
> # If its WAN
> if ($RunTimeKey{$siteId}->{'wan'} == 1) {
>
> # If its WAN1 resource, mark it INUSE and so on and so
forth...
>
> if ($Resources{'WAN1'}->{INUSE} == 0) {
> $Resources{'WAN1'}->{INUSE} = 1;
You have a race condition here. The variable you have just set could
have been changed by another thread since you tested it. You need some
sort of lock. See 'perldoc thread::shared' and 'perldoc perlthrtut'.
If you had one thread per resource, as suggested above, then this may
not even be necessary.
> dataHandler('WAN1',$siteId);
> $Resources{'WAN1'}->{INUSE} = 0;
> }
> elsif ($Resources{'WAN2'}->{INUSE} == 0) {
> $Resources{'WAN2'}->{INUSE} = 1;
> dataHandler('WAN2',$siteId);
> $Resources{'WAN2'}->{INUSE} = 0;
> }
> elsif ($Resources{'WAN3'}->{INUSE} == 0) {
> $Resources{'WAN3'}->{INUSE} = 1;
> dataHandler('WAN3',$siteId);
> $Resources{'WAN3'}->{INUSE} = 0;
> }
> elsif ($Resources{'WAN4'}->{INUSE} == 0) {
> $Resources{'WAN4'}->{INUSE} = 1;
> dataHandler('WAN4',$siteId);
> $Resources{'WAN4'}->{INUSE} = 0;
> }
> elsif ($Resources{'WAN5'}->{INUSE} == 0) {
> $Resources{'WAN5'}->{INUSE} = 1;
> dataHandler('WAN5',$siteId);
> $Resources{'WAN5'}->{INUSE} = 0;
> }
The above would be simpler as a loop over the keys of a table, which
would also be simpler if there were 2 resource tables. Also, what
happens if all resources are in use. For example:
>
> # If its NOT on the WAN make a modem call
>
> } elsif ($RunTimeKey{$siteId}->{'wan'} == 0) {
>
> if ($Resources{'POLL1'}->{INUSE} == 0) {
> $Resources{'POLL1'}->{INUSE} = 1;
> useModem($siteId);
> $Resources{'POLL1'}->{INUSE} = 0;
> }
> elsif ($Resources{'POLL2'}->{INUSE} == 0) {
> $Resources{'POLL2'}->{INUSE} = 1;
> useModem($siteId);
> $Resources{'POLL2'}->{INUSE} = 0;
> }
> elsif ($Resources{'POLL3'}->{INUSE} == 0) {
> $Resources{'POLL3'}->{INUSE} = 1;
> useModem($siteId);
> $Resources{'POLL3'}->{INUSE} = 0;
> }
> elsif ($Resources{'POLL4'}->{INUSE} == 0) {
> $Resources{'POLL4'}->{INUSE} = 1;
> useModem($siteId);
> $Resources{'POLL4'}->{INUSE} = 0;
> }
> elsif ($Resources{'POLL5'}->{INUSE} == 0) {
> $Resources{'POLL5'}->{INUSE} = 1;
> useModem($siteId);
> $Resources{'POLL5'}->{INUSE} = 0;
> }
> }
> }
>
>
#-----------------------------------------------------------------------
> -----
> # Routine that handles Modem Transfers
>
#-----------------------------------------------------------------------
> -----
> sub useModem {
> my ($siteId) = @_;
>
> print "Dialing modem for $siteId\n";
>
> return;
>
> }
>
>
#-----------------------------------------------------------------------
> -----
> # Routine that maps the drive and copies the data # Incomplete, due
> to Thread issues.
>
#-----------------------------------------------------------------------
> -----
> sub dataHandler {
>
> my ($resource,$siteId) = @_;
>
> print $resource." <- COMING IN\n";
>
> my $LocalName = $Resources{$resource}->{DRIVE};
> my $RemoteName = "\\\\".$RunTimeKey{$siteId}->{ip}."\\root";
> my $UpdateProfile = 0;
> my $User = $RunTimeKey{$siteId}->{userid};
> my $Password = $RunTimeKey{$siteId}->{password};
> my $Force = 1;
>
> print $LocalName." localname\n";
> print $RemoteName." remote name\n";
> print $UpdateProfile." updateprofile\n";
> print $User." username\n";
> print $Password." password\n";
> print $Force." force\n";
Use interpolation, it looks nicer.
>
>
> my $objnet=Win32::OLE->CreateObject("Wscript.Network");
>
> $objnet->MapNetworkDrive($LocalName, $RemoteName, $UpdateProfile,
> $User, $Password);
>
> print Win32::OLE->LastError();
>
> sleep (10);
>
> $objnet->RemoveNetworkDrive($LocalName, $Force, $UpdateProfile);
>
> return;
>
> }
As I said, get it working single threaded first. Then, if threading is
necessary, work out what threading model best suits your needs, and how
to organise your data structures so that they can be effectively and
efficiently shared between threads.
You should also bear in mind that threads are relatively new to Perl
(its not PERL, BTW), and although they seem to work reasonably well on
some platforms (including Win32), there are features that are not
available yet and some gotchas for the unwary. I would advise caution
before using them for anything critical.
HTH
--
Brian Raven
=================================
Atos Euronext Market Solutions Disclaimer
=================================
The information contained in this e-mail is confidential and solely for the
intended addressee(s). Unauthorised reproduction, disclosure, modification,
and/or distribution of this email may be unlawful.
If you have received this email in error, please notify the sender immediately
and delete it from your system. The views expressed in this message do not
necessarily reflect those of Atos Euronext Market Solutions.
L'information contenue dans cet e-mail est confidentielle et uniquement
destinee a la (aux) personnes a laquelle (auxquelle(s)) elle est adressee.
Toute copie, publication ou diffusion de cet email est interdite. Si cet e-mail
vous parvient par erreur, nous vous prions de bien vouloir prevenir
l'expediteur immediatement et d'effacer le e-mail et annexes jointes de votre
systeme. Le contenu de ce message electronique ne represente pas necessairement
la position ou le point de vue d'Atos Euronext Market Solutions.
_______________________________________________
ActivePerl mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs