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

I have 1 error and 1 warning messages (see below) for the following scripts with "A.pl" and "B.pm".

_A.pl_ ... my $dummy=1; threads->create("B::c", ($dummy)); ... _B.pm_ ... sub c{...} ...

ERROR_ "Scalars leaked: 1" occurs for each ref or a hash (replace $dummy with %dummy in above script) that is passed as argument to "B::c".

WARNING_ "Attempt to free unreferenced scalar" always happens in above example when we pass a variable (of any type) in one process to a sub in another module when it is run as a thread.

In all above cases, arguments have been initialized before creating threads. In "B::c", it also doesn't matter if those arguments appear as lef-side or right-side (the semaphore and queue definitely change their content and I also tried not to use any argument in "B::c" or just print out some scalar or size of some non-scalar.).

So, is this a problem of my script or a bug? I did find there is memory leak by checking w/ valgrind, though I haven't check in very detail. Any comments?


Thanks!

System:
perl v5.8.8 built for i686-linux-thread-multi
2.6.15-gentoo linux

Replies are listed 'Best First'.
Re: "Attempt to free unreferenced scalar" and "Scalars leaked: 1" ?
by Joost (Canon) on Mar 31, 2007 at 00:12 UTC

      Names "A" and "B" are used for simplicity. I didn't use them in real codes.

      The following gives short enough but clear code samples that result in 1 warning and 1 error messages that confused me.


      1. "Attempt to free unreferenced scalar" warning.
      for simplicity, there are 2 perl script files: test.pl and test.pm.
      _test.pl_
      use threads; use test; my $argument=1; my $thread=threads->create("forthread", ($argument)); $thread->join(); exit(0);

      _test.pm_
      package test; require Exporter; our @ISA =qw(Exporter); our @EXPORT =qw(queuereader); our @VERSION =1.0; sub forthread{ my ($arg)=@_; return 0; } #forthread

      NOTE: there is no problem if "forthread" is in test.pl. But when we put "forthread" in a separate file other than the caller file, it reports the above warning message, in fact, no matter if we pass any argument at time of thread creation.


      2. "Scalar leaked:1" error.
      It is for simplicity that bareword "argument" is used in place of any type of variable.
      _test.pl_
      use threads; use test; my $thread=threads->create("forthread", (argument)); $thread->join(); exit(0);

      -test.pm_
      package test; require Exporter; our @ISA =qw(Exporter); our @EXPORT =qw(queuereader); our @VERSION =1.0; sub forthread{ my (argument)=@_; my $thread=threads->create("another", (argument)); $thread->join(); return 0; } #forthread sub another{ return 0; } #another

      NOTE: the error is reported when "argument" is one of the following:
      - reference to scalar
      - reference to array
      - reference to hash
      - hash

        There are so many problems with your test code that you are almost certainly not testing the code you think you are. See the comments below:

        package test; require Exporter; our @ISA =qw(Exporter); our @EXPORT =qw(queuereader); ## You are exporting "queuereader" our @VERSION =1.0; sub forthread{ ## Not the forthread function that is in the f +ile! my ($arg)=@_; return 0; } #forthread ## You have no module termination value, 1;

        All of which leads me to believe that you aren't actually running this module when you run test.pl. Instead you are probably picking up another module called test from somewhere else.

        Now to test.pl

        use threads; use test; my $argument=1; ## VVVVVVVVVV---- this is not a function refe +rence, its a string! my $thread=threads->create("forthread", ($argument)); $thread->join(); exit(0);

        If I attempt to run this pair of files:

        ## test.pl use threads; use Testit; my $argument=1; my $thread=threads->create( 'forthread', ($argument)); $thread->join(); exit(0); ## Testit.pm package Testit; require Exporter; our @ISA =qw(Exporter); our @EXPORT =qw(forthread); our @VERSION =1.0; sub forthread{ my ($arg)=@_; warn "$arg"; return 0; } 1;

        I get the following output:

        C:\test>test.pl 1 at Testit.pm line 11. Attempt to free unreferenced scalar: SV 0x194aa50, Perl interpreter: 0 +x18290c4 during global destruction.

        Which shows that the function forthread has been exported from the package Testit into main, and has been run as a thread, but when the cleanup of the thread happens, it detects a leaked scalar--the string you passed.

        However, if I modify test.pl to pass a coderef rather than a string to the thread creation

        use threads; use Testit; my $argument=1; my $thread=threads->create( \&forthread, ($argument)); $thread->join(); exit(0); __END__ C:\test>test.pl 1 at Testit.pm line 11.

        I get no error. There are two ways of looking at this. The ability to pass a subroutine name as a string (and possibly a bareword if not using strict?) is a throwback to earlier time (perl 4?), but the code underlying the autoresolution of a string to a coderef is still embedded in the API code. However, newer modules and features may have been written by authors who never used this feature, and so their code does not cater for it.

        Specifically, the string containing the function name is duplicated as a string for use on the thread that will be created, but because the author(s) of the threads module where expecting a coderef, they do not deal with this situation. So the other way of looking at it is that this is a bug in the threads module somewhere.

        The simplest way of avoiding it is to pass a coderef in the first place.

        And when you post demo code, it would be nice if it actually worked to demonstrate the problem described :) test.pm is a bad choice of module/package name.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: "Attempt to free unreferenced scalar" and "Scalars leaked: 1" ?
by Khen1950fx (Canon) on Mar 30, 2007 at 23:59 UTC
    This is my first attempt at threads. I did a variation on your A.pl. I have perlv5.8.8, threaded and shared:

    #!/usr/bin/perl use strict; use warnings; use threads; use threads::shared; my $dummy : shared = 1; threads->new(sub { "B::c", $dummy++ })->join; print "$dummy\n";

      I don't know if I understand right, but the code seems to me the thread is based on code that resides in the same file as caller AND this thread will execute subroutine "c" in module B?

      threads->new(sub { "B::c", $dummy++ })->join;

      I really want to run a thread based on codes in different files other than the caller.