Thread overview
Thread join behaviour
Apr 14, 2012
Russel Winder
Apr 14, 2012
Matt Soucy
Apr 15, 2012
Russel Winder
Apr 14, 2012
Somedude
Apr 15, 2012
Russel Winder
April 14, 2012
I thought the following would terminate gracefully having printed 0..9
in some (random) order:

        #! /usr/bin/env rdmd

        import std.algorithm ;
        import std.range ;
        import std.stdio ;
        import core.thread ;

        int main ( immutable string[] args ) {
          auto threads = map ! ( ( int a ) {
              void delegate ( ) f ( ) {
                return delegate ( ) { writeln ( a ) ; } ;
              }
              return new Thread ( f )  ;
            } ) ( iota ( 10 ) ) ;
          foreach ( t ; threads ) { t.start ( ) ; }
          foreach ( t ; threads ) { t.join ( ) ; }
          return 0 ;
        }

However, this does not happen, at least with 2.059 on Linux as per Debian Unstable.  Instead I get:

        1
        2
        4
        5
        8
        3
        7
        6
        9
        0
        core.thread.ThreadException@src/core/thread.d(906): Unable to join thread
        ----------------
        /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) [0x425edb]
        /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void runMain()+0x17) [0x429bab]
        /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b]
        /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void runAll()+0x3d) [0x429bf9]
        /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b]
        /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) [0x4294c3]
        /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead]
        ----------------

I think I must be having a dumb moment as my reaction continues to be WTF.

-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel@winder.org.uk London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder


April 14, 2012
On 14-04-2012 18:04, Russel Winder wrote:
> I thought the following would terminate gracefully having printed 0..9
> in some (random) order:
>
>          #! /usr/bin/env rdmd
>
>          import std.algorithm ;
>          import std.range ;
>          import std.stdio ;
>          import core.thread ;
>
>          int main ( immutable string[] args ) {
>            auto threads = map ! ( ( int a ) {
>                void delegate ( ) f ( ) {
>                  return delegate ( ) { writeln ( a ) ; } ;
>                }
>                return new Thread ( f )  ;
>              } ) ( iota ( 10 ) ) ;
>            foreach ( t ; threads ) { t.start ( ) ; }
>            foreach ( t ; threads ) { t.join ( ) ; }
>            return 0 ;
>          }
>
> However, this does not happen, at least with 2.059 on Linux as per
> Debian Unstable.  Instead I get:
>
>          1
>          2
>          4
>          5
>          8
>          3
>          7
>          6
>          9
>          0
>          core.thread.ThreadException@src/core/thread.d(906): Unable to join thread
>          ----------------
>          /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) [0x425edb]
>          /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void runMain()+0x17) [0x429bab]
>          /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b]
>          /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void runAll()+0x3d) [0x429bf9]
>          /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b]
>          /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) [0x4294c3]
>          /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead]
>          ----------------
>
> I think I must be having a dumb moment as my reaction continues to be
> WTF.
>

http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_join.3.html#ERRORS

We can rule out these:

EDEADLK: Can't happen with your code.
EINVAL (second case): No other thread is trying to join.
ESRCH: Shouldn't happen since druntime registers threads with libpthread.

So, the first case of EINVAL (thread is not a joinable thread) must be the cause. I have no clue *why* though...

-- 
- Alex
April 14, 2012
On 04/14/2012 04:56 PM, Alex Rønne Petersen wrote:
> On 14-04-2012 18:04, Russel Winder wrote:
>> I thought the following would terminate gracefully having printed 0..9
>> in some (random) order:
>>
>> #! /usr/bin/env rdmd
>>
>> import std.algorithm ;
>> import std.range ;
>> import std.stdio ;
>> import core.thread ;
>>
>> int main ( immutable string[] args ) {
>> auto threads = map ! ( ( int a ) {
>> void delegate ( ) f ( ) {
>> return delegate ( ) { writeln ( a ) ; } ;
>> }
>> return new Thread ( f ) ;
>> } ) ( iota ( 10 ) ) ;
>> foreach ( t ; threads ) { t.start ( ) ; }
>> foreach ( t ; threads ) { t.join ( ) ; }
>> return 0 ;
>> }
>>
>> However, this does not happen, at least with 2.059 on Linux as per
>> Debian Unstable. Instead I get:
>>
>> 1
>> 2
>> 4
>> 5
>> 8
>> 3
>> 7
>> 6
>> 9
>> 0
>> core.thread.ThreadException@src/core/thread.d(906): Unable to join thread
>> ----------------
>> /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83)
>> [0x425edb]
>> /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern
>> (C) int rt.dmain2..main(int, char**).void runMain()+0x17) [0x429bab]
>> /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern
>> (C) int rt.dmain2..main(int, char**).void tryExec(scope void
>> delegate())+0x23) [0x42952b]
>> /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern
>> (C) int rt.dmain2..main(int, char**).void runAll()+0x3d) [0x429bf9]
>> /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern
>> (C) int rt.dmain2..main(int, char**).void tryExec(scope void
>> delegate())+0x23) [0x42952b]
>> /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3)
>> [0x4294c3]
>> /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead]
>> ----------------
>>
>> I think I must be having a dumb moment as my reaction continues to be
>> WTF.
>>
>
> http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_join.3.html#ERRORS
>
>
> We can rule out these:
>
> EDEADLK: Can't happen with your code.
> EINVAL (second case): No other thread is trying to join.
> ESRCH: Shouldn't happen since druntime registers threads with libpthread.
>
> So, the first case of EINVAL (thread is not a joinable thread) must be
> the cause. I have no clue *why* though...
>
If you merge the two foreach loops into one, doing t.start();t.join(); it doesn't have this issue. Also, when I run your code repeatedly the number of successful numbers printed changes a lot.
I'm assuming that you're trying to join a thread that already exited...
-Matt
April 14, 2012
Le 14/04/2012 18:04, Russel Winder a écrit :
> I thought the following would terminate gracefully having printed 0..9
> in some (random) order:
> 
>         #! /usr/bin/env rdmd
> 
>         import std.algorithm ;
>         import std.range ;
>         import std.stdio ;
>         import core.thread ;
> 
>         int main ( immutable string[] args ) {
>           auto threads = map ! ( ( int a ) {
>               void delegate ( ) f ( ) {
>                 return delegate ( ) { writeln ( a ) ; } ;
>               }
>               return new Thread ( f )  ;
>             } ) ( iota ( 10 ) ) ;
>           foreach ( t ; threads ) { t.start ( ) ; }
>           foreach ( t ; threads ) { t.join ( ) ; }
>           return 0 ;
>         }
> 
> However, this does not happen, at least with 2.059 on Linux as per Debian Unstable.  Instead I get:
> 
>         1
>         2
>         4
>         5
>         8
>         3
>         7
>         6
>         9
>         0
>         core.thread.ThreadException@src/core/thread.d(906): Unable to join thread
>         ----------------
>         /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) [0x425edb]
>         /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void runMain()+0x17) [0x429bab]
>         /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b]
>         /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void runAll()+0x3d) [0x429bf9]
>         /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b]
>         /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) [0x4294c3]
>         /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead]
>         ----------------
> 
> I think I must be having a dumb moment as my reaction continues to be WTF.
> 

This works:

int main ( immutable string[] args ) {

  auto threadgroup = new ThreadGroup();

  void delegate ( ) f (int a ) {
    return delegate ( ) { writeln ( a ) ; } ;
  }

  for ( int n = 0; n < 10; n++ ) {
    threadgroup.create(f(n));
  }
  threadgroup.joinAll( );
  return 0 ;
}

Threads are tracked by the threadgroup, which knows who can be joined.
April 15, 2012
On Sat, 2012-04-14 at 17:10 -0400, Matt Soucy wrote:
[...]
> If you merge the two foreach loops into one, doing t.start();t.join();
> it doesn't have this issue. Also, when I run your code repeatedly the
> number of successful numbers printed changes a lot.
> I'm assuming that you're trying to join a thread that already exited...

This matches with Artur's comment about laziness/strictness, but doing the above is only useful for experimentation, it cannot be a final solution since it enforces serialization of thread execution.

-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel@winder.org.uk London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder


April 15, 2012
On Sat, 2012-04-14 at 23:27 +0200, Somedude wrote:
[...]
> This works:
> 
> int main ( immutable string[] args ) {
> 
>   auto threadgroup = new ThreadGroup();
> 
>   void delegate ( ) f (int a ) {
>     return delegate ( ) { writeln ( a ) ; } ;
>   }
> 
>   for ( int n = 0; n < 10; n++ ) {
>     threadgroup.create(f(n));
>   }
>   threadgroup.joinAll( );
>   return 0 ;
> }
> 
> Threads are tracked by the threadgroup, which knows who can be joined.

Thanks for this, a useful alternative realization.

-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel@winder.org.uk London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder