mr_p has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Monks,

Here is the code that is giving me problems. Sorry for posting again: But it seem like was not posted last time I tried.

The problem is @ftpDirectoryListing and @deDuppedArray both become arrays with Interger values and If I change them to 'undef' then I get the above error.

This is the error I get if I change it to undef: Can't use an undefined value as an ARRAY reference at /nss/nfx/shmem/lib/lib/perl5/site_perl//5.8.5/IPC/Shareable.pm line 446.

#! /usr/bin/perl -w use strict; use lib "/nss/nfx/shmem/lib/lib"; use lib "/nss/nfx/shmem/lib/lib64"; use lib "/nss/nfx/shmem/lib/lib/perl5/site_perl/"; use File::Basename; use Getopt::Long; use File::Copy; use Data::Dumper; use strict; ###################### ######## Shared Memory Decl. ######### use IPC::Shareable; ################ my $child; my $serv_id; my $maxRcvrCount; my $stripeInstance; my $maxStripeInstance; my $user; my @ftpDirectoryListing=(); my @deDuppedArray=(); my @filesDownloaded=(); my $glue = 'data'; my %options = ( create => 1, exclusive => 0, mode => 0644, destroy => 0, ); my $deDuppedArrayHandle = tie @deDuppedArray, 'IPC::Shareable', undef, + \%options; my $filesDownloadedHandle = tie @filesDownloaded, 'IPC::Shareable', un +def, \%options; sub pollDaemonParent { my $error = ""; my $user = $_[0]; my $tmpIntervalHolder = .5; my @previousListing=(); my @currentListing=(); ConnectAndLogin(); while (1) { @previousListing = @currentListing; @currentListing = getListing($user); $deDuppedArrayHandle->shlock(); @deDuppedArray = deDupArray1(\@previousListing, \@currentListi +ng); if ($#deDuppedArray >= 0) { print "\nParent: currentListing: @currentListing deDupp +edArray: @deDuppedArray\n"; } $deDuppedArrayHandle->shunlock(); deleteRemoteFiles1(); select (undef, undef, undef,$tmpIntervalHolder); } } sub deleteRemoteFiles1 { # TODO: Get list and delete from server. once deleted $filesDownloadedHandle->shlock(); if ($#filesDownloaded >= 0) { print "\nParent: deleteListing: @filesDownloaded\n"; } foreach (@filesDownloaded) { print "Deleting File: $_\n"; } @filesDownloaded=(); $filesDownloadedHandle->shunlock(); } sub pollDaemonChild { my $error = ""; my $user = $_[0]; my $tmpIntervalHolder = 1; print "ChildStarted: $stripeInstance\n"; while (1) { @ftpDirectoryListing = (); $deDuppedArrayHandle->shlock(); @ftpDirectoryListing = @deDuppedArray; $deDuppedArrayHandle->shunlock(); if ($#ftpDirectoryListing >= 0) { print "Child: @ftpDirectoryListing\n"; } select (undef, undef, undef,$tmpIntervalHolder); processList($user); } } sub ConnectAndLogin { return; } sub getListing { my @ftpListing1 = (); push (@ftpListing1, "abc.xml"); push (@ftpListing1, "xyz.xml"); return @ftpListing1; } sub deDupArray1 { my ($previousArray, $currentArray) = @_; my @union;my @intersection;my@difference; @union = @intersection = @difference = (); my %count = (); my $element=""; ################################################################## +################################### # get Difference of two arrays. ################################################################## +################################### # go into foreach loop for any element that exist in both previous +Array and currentArray and increment # count of element value. foreach $element (@$previousArray, @$currentArray) { $count{$element}++ } foreach $element (keys %count) { #print "$element:$count{$element}\n"; push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference } +, $element; } ################################################################## +################################### # Remove any element that existed in previous list from not in cur +rent list. ################################################################## +################################### my @elements_needs_to_be_removed = (@intersection, @$previousArray +); %count = (); foreach $element (@elements_needs_to_be_removed, @difference) { $count{$element}++ } @difference=(); foreach $element (keys %count) { # print "$element:$count{$element} "; push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference } +, $element; } return @difference; } sub addToDeleteList { $|++; #print "\nAdding file to Delete List: $_[0]\n"; $filesDownloadedHandle->shlock(); push (@filesDownloaded, "$_[0]"); $filesDownloadedHandle->shunlock(); } # main { $user = "IAmUser"; $serv_id = "1"; $maxRcvrCount = "5"; $stripeInstance = "1" ; $maxStripeInstance = "2"; $SIG{'ALRM'} = 'sig_alrm'; my $startingInstanceNum=1; my @kids; for (1 .. $maxStripeInstance) { $stripeInstance = $startingInstanceNum; print "stripeInstance: $startingInstanceNum\n"; unless ($child = fork) { # i'm the child die "cannot fork: $!" unless defined $child; pollDaemonChild($user); exit; } push @kids, $child; # in case we care about their pids $startingInstanceNum++; } print "@kids\n"; pollDaemonParent($user); }
  • Comment on undefined value as an ARRAY reference: Using Tie with IPC::Shareable : New Code.
  • Download Code

Replies are listed 'Best First'.
Re: undefined value as an ARRAY reference: Using Tie with IPC::Shareable : New Code.
by BioLion (Curate) on Oct 08, 2009 at 10:41 UTC

    It would be a great help if you could boil this code down to something small which reproduces the error, it might also help you work out why you are getting the error.

    Looking at how you are using IPC::Shareable I think this is the root of the issue - If you look at the documents, you should be tie-ing variables like so:

    use strict; use IPC::Shareable; my $glue = 'data'; my %options = ( create => 'yes', exclusive => 0, mode => 0644, destroy => 'yes', ); my %colours; tie %colours, 'IPC::Shareable', $glue, { %options } or die "server: tie failed\n";

    Not like you did, ($deDuppedArrayHandle is effectively the return value of the tie, not a handle on the tied variable) :

    my $glue = 'data'; my %options = ( create => 1, exclusive => 0, mode => 0644, destroy => 0, ); my $deDuppedArrayHandle = tie @deDuppedArray, 'IPC::Shareable', undef, + \%options; my $filesDownloadedHandle = tie @filesDownloaded, 'IPC::Shareable', un +def, \%options;

    IPC::Shareable docs tells you that

    "The association between variables in distinct processes is provided by GLUE. This is an integer number or 4 character string1 that serves as a common identifier for data across process space."
    While you define $glue you don't actually use it in the tie, and furthermore you then use undef as the 'glue' for both your ties.

    IPC::Shareable also tells you that

    "exclusive If exclusive field is set to a true value, calls to tie() will fail (returning undef) if a data binding associated with GLUE already exists. If set to a false value, calls to tie() will succeed even if a shared memory segment associated with GLUE already exists. The default is false "

    The result of which is that I would imagine that either your ties are failing (and returning undef) or the tie is working, but you are then overwriting the first tie (because you didn't make the tie exclusive, or provide an alternate glue), so when you come to use it, the data isn't there. I would suspect the first though.

    I might be wrong about your error (i haven't tested my theory), but IPC::Shareable can be hard to use properly, so when i do, i stick rigidly to the examples given, or experiment fully before deploying it in anything important! HTH!

    Just a something something...
      You're wrong about him being wrong concerning tie's return value.
      my $deDuppedArrayHandle = tie @deDuppedArray, 'IPC::Shareable', undef, + \%options;
      is short for
      tie @deDuppedArray, 'IPC::Shareable', undef, \%options; my $deDuppedArrayHandle = tied @deDuppedArray;

      tie, tied