Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

incorrect return value for threads::join() #8174

Closed
p5pRT opened this issue Oct 30, 2005 · 13 comments
Closed

incorrect return value for threads::join() #8174

p5pRT opened this issue Oct 30, 2005 · 13 comments

Comments

@p5pRT
Copy link

p5pRT commented Oct 30, 2005

Migrated from rt.perl.org#37564 (status was 'resolved')

Searchable as RT37564$

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2005

From wendigo@jabberwock.org

This is a bug report for perl from wendigo@​jabberwock.org,
generated with the help of perlbug 1.35 running under perl v5.8.7.


It looks like the threads​::join() function is returning undef when it should
be returning a scalar.

What the manpage says​:

  $thread->join
  This will wait for the corresponding thread to join. When the
  thread finishes, join() will return the return values of the entry
  point function. If the thread has been detached, an error will be
  thrown.

What threads v1.05 actually does​:

--
#!/usr/local/bin/perl
use threads;

sub foo {
  my $rv = shift;
  my $id = threads->self->tid;
  print "$id returning $rv\n";
  return $rv;
}

for my $val (0..2) {
  threads->create(\&foo, $val);
}

foreach my $t (threads->list) {
  if ($t->tid && ! threads​::equal($t, threads->self)) {
  my $rv = $t->join;
  my $id = $t->tid;
  print "$id returned $rv\n";
  }
}
--

1 returning 0
2 returning 1
3 returning 2
1 returned
2 returned
3 returned



Flags​:
  category=core
  severity=low


Site configuration information for perl v5.8.7​:

Configured by wendigo at Mon Oct 24 11​:24​:44 EDT 2005.

Summary of my perl5 (revision 5 version 8 subversion 7) configuration​:
  Platform​:
  osname=linux, osvers=2.6.8-2-386, archname=i686-linux-thread-multi
  uname='linux phoenix 2.6.8-2-386 #1 thu may 19 17​:40​:50 jst 2005 i686 gnulinux '
  config_args=''
  hint=recommended, useposix=true, d_sigaction=define
  usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
  useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
  use64bitint=undef use64bitall=undef uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-O2',
  cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -fno-strict-aliasing -pipe -I/usr/local/include'
  ccversion='', gccversion='3.3.5 (Debian 1​:3.3.5-13)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=4, prototype=define
  Linker and Libraries​:
  ld='gcc', ldflags =' -L/usr/local/lib'
  libpth=/usr/local/lib /lib /usr/lib
  libs=-lnsl -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
  perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
  libc=/lib/libc-2.3.2.so, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.3.2'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
  cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches​:
 


@​INC for perl v5.8.7​:
  /usr/local/lib/perl5/5.8.7/i686-linux-thread-multi
  /usr/local/lib/perl5/5.8.7
  /usr/local/lib/perl5/site_perl/5.8.7/i686-linux-thread-multi
  /usr/local/lib/perl5/site_perl/5.8.7
  /usr/local/lib/perl5/site_perl
  .


Environment for perl v5.8.7​:
  HOME=/home/wendigo
  LANG=en_US
  LANGUAGE=en_US​:en_GB​:en
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/local/bin​:/usr/bin​:/bin​:/usr/X11R6/bin​:/usr/games
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2005

From robin@cpan.org

Believe it or not, this is (almost) a documented feature. The
documentation for $thread->join() says​:

  The context (scalar or list) of the thread creation is also the
  context for join().

(My "almost" is because this should really say "void, scalar or list".)

Your code is calling create() in void context, so join() isn't
returning anything. If you call create() in scalar context, for example

  for my $val (0..2) {
  my $unused = threads->create(\&foo, $val);
  }

then it works as expected.

Of course this is totally insane, but there you go.

Robin

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2005

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2005

From @lizmat

At 11​:07 PM +0000 10/30/05, Robin Houston wrote​:

Believe it or not, this is (almost) a documented feature. The
documentation for $thread->join() says​:

The context (scalar or list) of the thread creation is also the
context for join().

(My "almost" is because this should really say "void, scalar or list".)

Your code is calling create() in void context, so join() isn't
returning anything. If you call create() in scalar context, for example

for my $val \(0\.\.2\) \{

my $unused = threads->create(\&foo, $val);
}

then it works as expected.

Of course this is totally insane, but there you go.

Well, consider how you would communicate the context in which the
join is to be executed into the thread, particularly when excution of
the thread is finished way before the join() is reached in the parent
thread.

More exactly​: there could be a check for "wantarray" in the beginning
of the execution of the thread. How can that have a sane value?
Would you want execution of the thread to halt until the join() is
reached? Then why would you need a thread then.

So I think the behaviour is maybe a little surprising, there is
definitely a, in my opinion, sound logic behind it.

Now in an ideal world you could maybe set up different return values
inside the thread depending on possible context, and have perl select
the right set of values depending of the context of the join().
Maybe not Perl 5, maybe Perl 6. Who knows.

Liz

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2005

From @rgarcia

Robin Houston wrote​:

(My "almost" is because this should really say "void, scalar or list".)

Thanks, changed as #25912.

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2005

From robin@cpan.org

More exactly​: there could be a check for "wantarray" in the beginning
of the execution of the thread. How can that have a sane value?
Would you want execution of the thread to halt until the join() is
reached? Then why would you need a thread then.

I understand that the context needs to be determined in advance,
but using the context of the create() call is both inflexible and
hopelessly confusing.

Suppose you want the thread to be in void context, but you also
need the thread object. You're out of luck, unless you do something
like

  threads->new(\&foo); # void context!
  my $thread = (threads->list)[-1];

which might not work, because some other thread might create a
new thread in between the two statements. And it's desperately
cryptic to choose list context by writing

  my ($thread) = threads->new(\&bar);

A more sensible approach, IMO, would be to specify the context
explicitly, defaulting to scalar. e.g.

  my $thread1 = threads->create(\&foo, 'void');
  my $thread2 = threads->create(\&bar, 'list');

but I fear it may be too late to change this.

Robin

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2005

From @lizmat

At 9​:50 AM +0000 10/31/05, Robin Houston wrote​:

More exactly​: there could be a check for "wantarray" in the beginning
of the execution of the thread. How can that have a sane value?
Would you want execution of the thread to halt until the join() is
reached? Then why would you need a thread then.

I understand that the context needs to be determined in advance,
but using the context of the create() call is both inflexible and
hopelessly confusing.

I guess the alternative would have been to only allow a single scalar
value to be returned by join(). Regardless of context of the
create(). That would have made sense and would have been both clear
and flexible enough, but unfortunately I was not involved with
ithreads when the decision was made to take the context of create().

Suppose you want the thread to be in void context, but you also
need the thread object. You're out of luck, unless you do something
like

threads->new(\&foo); # void context!
my $thread = (threads->list)[-1];

which might not work, because some other thread might create a
new thread in between the two statements. And it's desperately
cryptic to choose list context by writing

my ($thread) = threads->new(\&bar);

If you need the thread to be joined in void context, just join it in
void context. What is the problem with that?

A more sensible approach, IMO, would be to specify the context
explicitly, defaulting to scalar. e.g.

my $thread1 = threads->create(\&foo, 'void');
my $thread2 = threads->create(\&bar, 'list');

but I fear it may be too late to change this.

Indeed, because 'void' and 'list' would just be passed as parameters
to &foo and &bar.

I think that actually even more context would have been more
appropriate, so that you not only would know that the subroutine
should return in void/scalar/list context, but also that you would
know that you're the start of a new thread and that returning from
that sub would actually stop the thread. Something that Perl6 will
probably / hopefully bring.

Liz

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2005

From robin@cpan.org

On Mon, Oct 31, 2005 at 11​:05​:32AM +0200, Elizabeth Mattijsen wrote​:

I guess the alternative would have been to only allow a single scalar
value to be returned by join(). Regardless of context of the
create(). That would have made sense and would have been both clear
and flexible enough, but unfortunately I was not involved with
ithreads when the decision was made to take the context of create().

I agree, that would have been fine. I have no idea who made this
decision, and I'm certainly not blaming you! (Nor am I trying to
blame whoever did make the decision. I'm only wondering if there
is a way to improve matters.)

If you need the thread to be joined in void context, just join it in
void context. What is the problem with that?

It won't cause the sub to be *called* in void context.

Indeed, because 'void' and 'list' would just be passed as parameters
to &foo and &bar.

That was a very bad choice of example syntax. Sorry!

Robin

@p5pRT
Copy link
Author

p5pRT commented Oct 31, 2005

From @lizmat

At 10​:31 AM +0000 10/31/05, Robin Houston wrote​:

On Mon, Oct 31, 2005 at 11​:05​:32AM +0200, Elizabeth Mattijsen wrote​:

I guess the alternative would have been to only allow a single scalar
value to be returned by join(). Regardless of context of the
create(). That would have made sense and would have been both clear
and flexible enough, but unfortunately I was not involved with
ithreads when the decision was made to take the context of create().

I agree, that would have been fine. I have no idea who made this
decision, and I'm certainly not blaming you! (Nor am I trying to
blame whoever did make the decision. I'm only wondering if there
is a way to improve matters.)

If you need the thread to be joined in void context, just join it in
void context. What is the problem with that?

It won't cause the sub to be *called* in void context.

Indeed, because 'void' and 'list' would just be passed as parameters
to &foo and &bar.

That was a very bad choice of example syntax. Sorry!

Maybe this would help as a temporary fix​:

sub threads​::create_to_join_as_list { (shift->create( @​_ ))[0] };

my $thread = threads->create_to_join_as_list( sub { (1,2,3) } );

print "thread = $thread\n";

my @​result = $thread->join;

print "result = @​result\n";
__END__
thread = threads=SCALAR(0x18014b8)
result = 1 2 3

Liz

@p5pRT
Copy link
Author

p5pRT commented Nov 2, 2005

From wendigo@pobox.com

An entity claiming to be Robin Houston (robin@​cpan.org) wrote​:
:
: (My "almost" is because this should really say "void, scalar or list".)
:

Ok, that explains it.

:
: Of course this is totally insane, but there you go.
:

I don't know if it's necessarily insane. If you want a thread executed in
void context, is having the ID actually necessary?

An entity claiming to be Elizabeth Mattijsen via RT (perlbug-followup@​perl.org) wrote​:
:
: sub threads​::create_to_join_as_list { (shift->create( @​_ ))[0] };
:
: my $thread = threads->create_to_join_as_list( sub { (1,2,3) } );
:

I think an approach like this is probably best. Although, I am partial to
terse method names along the lines of createv, creates, and createl.

--
[] | Use what talents you possess​: the woods
[] Mark Rogaski | would be very silent if no birds sang
[] wendigo@​pobox.com | except those that sang best.
[] mrogaski@​cpan.org | -- Henry Van Dyke
[] |

@p5pRT
Copy link
Author

p5pRT commented May 25, 2006

From guest@guest.guest.xxxxxxxx

[robin@​cpan.org - Mon Oct 31 01​:51​:41 2005]​:
A more sensible approach, IMO, would be to specify the context
explicitly

This is now addressed with change #28291.

@p5pRT
Copy link
Author

p5pRT commented Nov 18, 2009

From @jdhedden

On Thu May 25 06​:57​:05 2006, guest wrote​:

[robin@​cpan.org - Mon Oct 31 01​:51​:41 2005]​:
A more sensible approach, IMO, would be to specify the context
explicitly

This is now addressed with change #28291.

Confirmed. This bug is fixed.

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2010

@cpansprout - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant