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

I'm new to using threads so I was trying a quick program to illustrate the concept with Net::Ping. My code takes a number of networks as CL options and sends each to a thread (in a sub). Then, each host in each network is sent to another thread (in a sub) and ping'd. Pretty simple (apologies for the length of code):

use strict; use warnings; use Getopt::Long qw(:config no_ignore_case); #bundling use Pod::Usage; use threads; use Net::Ping; ######## my %opts; my ($opt_help, $opt_man); GetOptions( 'start=i' => \$opts{'start'}, 'Stop=i' => \$opts{'stop'}, 'Threads=i' => \$opts{'threads'}, 'help!' => \$opt_help, 'man!' => \$opt_man, ) or pod2usage(-verbose => 0); if (!@ARGV) { pod2usage(-verbose => 0, -message => "$0: network required\n") } ######## if (!defined($opts{'start'})) { $opts{'start'} = 1 } if (!defined($opts{'stop'})) { $opts{'stop'} = 254 } if (!defined($opts{'threads'})) { $opts{'threads'} = 5 } if ($opts{'start'} > $opts{'stop'}) { print "$0: start is greater than stop\n"; exit 1 } my @th; my $count = 0; for (@ARGV) { if ($_ !~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.\d{1,3}$/) { print "$0: $_ is not valid network, skipping ...\n"; next } $opts{'net'} = $1 . "." . $2 . "." . $3 . "."; print "Pinging network: $opts{'net'}0\n"; $th[$count++] = threads->create(\&THPING, \%opts) } for (@th) { $_->join } sub THPING { my ($args) = @_; my @th; my $count = 0; for ($args->{'start'}..$args->{'stop'}) { print " Pinging host: $args->{'net'}$_\n"; $th[$count++] = threads->create(\&PINGIT, $args->{'net'} . $_) } for (@th) { $_->join } return 0 } sub PINGIT { my ($addr) = @_; my $p = Net::Ping->new(); if ($p->ping($addr)) { print "$addr is alive.\n" } else { print "$addr is DEAD.\n" } $p->close(); return 0 }

When run with the following, I get:

{C} > test 172.18.7.0 172.18.6.0 -s 31 -S 35 Pinging network: 172.18.7.0 Pinging host: 172.18.7.31 Pinging host: 172.18.7.32 Pinging network: 172.18.6.0 Pinging host: 172.18.7.33 Pinging host: 172.18.7.34 Pinging host: 172.18.7.35 Pinging host: 172.18.6.31 Pinging host: 172.18.6.32 Pinging host: 172.18.6.33 Pinging host: 172.18.6.34 Pinging host: 172.18.6.35 172.18.7.31 is alive. 172.18.7.33 is alive. 172.18.7.34 is alive. 172.18.7.32 is alive. 172.18.7.35 is alive. Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 172.18.6.33 is DEAD. 172.18.6.31 is DEAD. 172.18.6.34 is DEAD. 172.18.6.35 is DEAD. 172.18.6.32 is DEAD. Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1

Expected results and everything is fine ... except for those pesky "Scalars leaked: 1" warnings. FYI:

{C} > ver Microsoft Windows XP [Version 5.1.2600] {C} > perl -v | head -8 This is perl, v5.10.1 built for MSWin32-x86-multi-thread (with 2 registered patches, see perl -V for more detail) Copyright 1987-2009, Larry Wall Binary build 1006 [291086] provided by ActiveState http://www.ActiveSt +ate.com Built Aug 24 2009 13:48:26 {C} > perl -V | grep threads useithreads=define, usemultiplicity=define

I've done a lot of reading/research on the "Scalars leaked" - including first reading the Perl 'Threads' tutorial - and even found some Perlmonks.org hits; however, they seem to indicate this isn't something to worry about. I certainly don't want my program(s) spitting warnings/errors if there is a way to resolve them.

Is there an easy fix here that a beginner is overlooking? Am I breaking some 'thread' rules in that I shouldn't be creating threads in threads?

(Again, this is a 'proof-of-concept' for me to understand threads, I understand there could be a problem with input ... say 20 networks on the CL each pinging 255 hosts - 5100 threads! Some more rigorous checking/controls are needed in the future).

Update: Added 'readmore' tags - didn't realize it got front-paged. In the future I'll write posts with that contingency in mind.

Replies are listed 'Best First'.
Re: Threads: How to fix "Scalars leaked" Issue?
by gmargo (Hermit) on Nov 17, 2009 at 15:57 UTC

    I believe the "leaked scalar" is the reference to %opts passed to the threads.

    When I modified the code to pass the network, start, and stop parameters explicitly, instead of through the $args reference, the "leaked" message went away.

      ++ Votes for you! That fixed it for me too. I'm still curious as to why passing the hash and using the references gave issues?

      I was trying to make my life easier by passing a reference to a hash rather than each individual option.

Re: Threads: How to fix "Scalars leaked" Issue?
by ikegami (Patriarch) on Nov 17, 2009 at 16:22 UTC

    To debug problems like this, eliminate what doesn't matter until you find what does matter. This is the code you should have posted:

    use strict; use warnings; use threads; sub PINGIT { print "PINGIT\n"; return 0; } sub THPING { print "THPING\n"; my @th; for (1..5) { push @th, threads->create(\&PINGIT); } $_->join for @th; return 0; } { my %opts; my @th; for (1..2) { if ($ARGV[0]) { # Doesn't generate error message push @th, threads->create(\&THPING); } else { # Generate error message push @th, threads->create(\&THPING, \%opts); } } $_->join for @th; }
    >perl 807726.pl 0 THPING THPING PINGIT PINGIT PINGIT PINGIT PINGIT Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 PINGIT PINGIT PINGIT Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 PINGIT PINGIT Scalars leaked: 1 Scalars leaked: 1 Scalars leaked: 1 >perl 807726.pl 1 THPING THPING PINGIT PINGIT PINGIT PINGIT PINGIT PINGIT PINGIT PINGIT PINGIT PINGIT

    I don't know why that gives an error. It could very well be a bug in Perl. (See perlbug if you wish to submit a bug report.)

    The problem is not specific to a version of Perl (reproduced on 5.8.0, 5.8.8, 5.10.0, 5.10.1) or to an OS (reproduced on WinXP, Linux).

Re: Threads: How to fix "Scalars leaked" Issue? (Workaround)
by ikegami (Patriarch) on Nov 17, 2009 at 17:59 UTC
    I found a simple workaround. Change
    sub THPING { my ($args) = @_; ... } sub PINGIT { my ($addr) = @_; ... }

    to

    sub THPING { my ($args) = @_; @_=(); # Avoid leaking. ... } sub PINGIT { my ($addr) = @_; @_=(); # Avoid leaking. ... }

    (or shift the args out)

Re: Threads: How to fix "Scalars leaked" Issue?
by ikegami (Patriarch) on Jan 11, 2010 at 16:21 UTC