Thread overview
Thread questions
Oct 07, 2004
novice
Oct 07, 2004
Ben Hinkle
Oct 07, 2004
novice
Oct 07, 2004
Ben Hinkle
Oct 07, 2004
Ben Hinkle
Oct 09, 2004
Ben Hinkle
Oct 07, 2004
Burton Radons
Oct 07, 2004
Sjoerd van Leent
Oct 07, 2004
Sean Kelly
Oct 07, 2004
Sjoerd van Leent
October 07, 2004
Hello everybody.

Q1:
Class Thread in std.thread.d has constructor this(int (*fp)(void *), void *arg),
i.e. (if i understand) thread function must return int value.
But i can't find, how obtain this value.
I found Windows API GetExitCodeThread. But, may be, Thread class have ability to
get the value, returned by thread function?

Q2:
For what we have run() method of Thread class?

Thanks!


October 07, 2004
novice wrote:

> Hello everybody.
> 
> Q1:
> Class Thread in std.thread.d has constructor this(int (*fp)(void *), void
> *arg), i.e. (if i understand) thread function must return int value.
> But i can't find, how obtain this value.
> I found Windows API GetExitCodeThread. But, may be, Thread class have
> ability to get the value, returned by thread function?

Why do you want to obtain the thread return value? Usually you just return 0 at the end of fp() to mean "the thread ended normally".

> Q2:
> For what we have run() method of Thread class?

It seems strange I guess but run() will immediately run the thread callback in the current thread instead of starting a new thread. I suppose it is handy if you change you mind before actually starting the other thread.

> 
> Thanks!

October 07, 2004
Thank you, Ben Hinkle.

>Why do you want to obtain the thread return value?

I need to pass some results of child thread's to parent (main) thread.

>handy if you change you mind before actually starting the other thread.

:)


October 07, 2004
"novice" <novice_member@pathlink.com> wrote in message news:ck3g33$1em3$1@digitaldaemon.com...
> Thank you, Ben Hinkle.
>
> >Why do you want to obtain the thread return value?
>
> I need to pass some results of child thread's to parent (main) thread.

Be aware that thre return value for a thread is the pass/fail status flag
and shouldn't be used to return the result of some computation. If you want
to communicate the result of a computation I'd use a shared resource and
pass that to the thread. For example
import std.thread;
int main() {
 int *res;
 res = new int;
 Thread t = new Thread(function int(void*vptr) {
    int*res = cast(int*)vptr;
    *res = 100*100; // your code here
    return 0;
    },res);
 t.start();
 //... do something until thread finishes
 printf("%d\n",*res);
 return 0;
}
Or you can use delegates and reference the stack of the calling thread
directly (as long as the calling function doesn't return while the child
thread is running).

You might want to check out the Locks library for some handy threading
functions. For more info see
http://home.comcast.net/~benhinkle/mintl/locks.html. With dmd-102 I've been
getting some pretty strange behaviors so please report bugs to me. I
typically get fewer bugs with the library compiled without -O or unittests.
Here is a test program that uses CountDownLatches to coordinate threads and
a ReentrantLock to control access to a counter.
import locks.all;
import std.thread;
int main() {
  CountDownLatch go = new CountDownLatch(1);
  CountDownLatch allDone = new CountDownLatch(4);
  Thread[4] t;
  int total;
  ReentrantLock lock = new ReentrantLock;
  for (int i=0; i < 4; i++) {
    t[i] = new Thread(
      delegate int() {
        go.wait(); // wait for signal from main thread
        // ... do something interesting ...
        lock.lock();
        total += 100;
 for(int k=0;k<1000000;k++) { } // seems to need a pause?
        lock.unlock();
        allDone.countDown();
        return 0;
      });
    t[i].start();
  }
  go.countDown(); // let worker threads go
  allDone.wait(); // wait for all workers to finish
  printf("%d\n",total); // total should now be 400
  return 0;
}

But back to your original question, I don't know how to get the return value after the thread is done.

-Ben


October 07, 2004
> import locks.all;
> import std.thread;
> int main() {
>   CountDownLatch go = new CountDownLatch(1);
>   CountDownLatch allDone = new CountDownLatch(4);
>   Thread[4] t;
>   int total;
>   ReentrantLock lock = new ReentrantLock;
>   for (int i=0; i < 4; i++) {
>     t[i] = new Thread(
>       delegate int() {
>         go.wait(); // wait for signal from main thread
>         // ... do something interesting ...
>         lock.lock();
>         total += 100;
>  for(int k=0;k<1000000;k++) { } // seems to need a pause?
>         lock.unlock();
>         allDone.countDown();
>         return 0;
>       });
>     t[i].start();
>   }
>   go.countDown(); // let worker threads go
>   allDone.wait(); // wait for all workers to finish
>   printf("%d\n",total); // total should now be 400
>   return 0;
> }

I should add that in this example the ReentantLock can also be replaced with
 synchronized {
    total += 100;
 }


October 07, 2004
novice wrote:

> Thank you, Ben Hinkle.
> 
> 
>>Why do you want to obtain the thread return value?
> 
> 
> I need to pass some results of child thread's to parent (main) thread.

You might want to use an asynchronous return structure for that, such as this:

    import std.thread;

    struct AsynchronousReturn (ReturnType)
    {
        bit finished; /**< Set to true when execution has finished. */
        ReturnType value; /**< Return value. */

        ReturnType delegate () func; /**< The function being executed. */

        /** Execute the function, assign value, and set finished to true. */
        int run ()
        {
            value = func ();
            finished = true;
            return 0;
        }

        /** Execute the function in another thread, assign value, and set finished once done. */
        void execute (ReturnType delegate () func)
        {
            finished = false;
            this.func = func;
            (new Thread (&run)).start ();
        }
    }

    void test ()
    {
        AsynchronousReturn! (int) async;

        async.execute (delegate int ()
        {
            int length;

            for (int c; c < 10; c ++)
            {
                length += printf ("flah %d\n", c);
                Thread.yield ();
            }

            return length;
        });

        while (!async.finished)
        {
            printf ("waiting...\n");
            Thread.yield ();
        }
        printf ("returned %d!\n", async.value);
    }

Then you can return whatever you want.
October 07, 2004
Burton Radons wrote:
> novice wrote:
> 
>> Thank you, Ben Hinkle.
>>
>>
>>> Why do you want to obtain the thread return value?
>>
>>
>>
>> I need to pass some results of child thread's to parent (main) thread.
> 
> 
> You might want to use an asynchronous return structure for that, such as this:
> 
>     import std.thread;
> 
>     struct AsynchronousReturn (ReturnType)
>     {
>         bit finished; /**< Set to true when execution has finished. */
>         ReturnType value; /**< Return value. */
> 
>         ReturnType delegate () func; /**< The function being executed. */
> 
>         /** Execute the function, assign value, and set finished to true. */
>         int run ()
>         {
>             value = func ();
>             finished = true;
>             return 0;
>         }
> 
>         /** Execute the function in another thread, assign value, and set finished once done. */
>         void execute (ReturnType delegate () func)
>         {
>             finished = false;
>             this.func = func;
>             (new Thread (&run)).start ();
>         }
>     }
> 
>     void test ()
>     {
>         AsynchronousReturn! (int) async;
> 
>         async.execute (delegate int ()
>         {
>             int length;
> 
>             for (int c; c < 10; c ++)
>             {
>                 length += printf ("flah %d\n", c);
>                 Thread.yield ();
>             }
> 
>             return length;
>         });
> 
>         while (!async.finished)
>         {
>             printf ("waiting...\n");
>             Thread.yield ();
>         }
>         printf ("returned %d!\n", async.value);
>     }
> 
> Then you can return whatever you want.

Looks good. I would mention one thin, declare AsynchronousReturn as class (such that it can be send to other functions) and declare finished and value as private and add two routines that get the value, else one could break the functionality by setting the finished state to whatever someone wants (the same goes for value).

For the rest, nice work (Well I think it is nice work ;-) )

Regards,
Sjoerd
October 07, 2004
In article <ck3ump$1rnr$1@digitaldaemon.com>, Sjoerd van Leent says...
>
>Looks good. I would mention one thin, declare AsynchronousReturn as class (such that it can be send to other functions) and declare finished and value as private and add two routines that get the value, else one could break the functionality by setting the finished state to whatever someone wants (the same goes for value).

Since we're being picky, make the updates of finished and value atomic.  You could probably use CompareAndSwap from MinTL.  This should take care of memory visibility.  The alternate would be to wrap the reads and writes in a synchronized block.


Sean


October 07, 2004
Sean Kelly wrote:
> In article <ck3ump$1rnr$1@digitaldaemon.com>, Sjoerd van Leent says...
> 
>>Looks good. I would mention one thin, declare AsynchronousReturn as class (such that it can be send to other functions) and declare finished and value as private and add two routines that get the value, else one could break the functionality by setting the finished state to whatever someone wants (the same goes for value).
> 
> 
> Since we're being picky, make the updates of finished and value atomic.  You
> could probably use CompareAndSwap from MinTL.  This should take care of memory
> visibility.  The alternate would be to wrap the reads and writes in a
> synchronized block.
> 
> 
> Sean
> 
> 

I just had a bad day...

Regards,
Sjoerd
October 09, 2004
>import locks.all;
>import std.thread;
>int main() {
>  CountDownLatch go = new CountDownLatch(1);
>  CountDownLatch allDone = new CountDownLatch(4);
>  Thread[4] t;
>  int total;
>  ReentrantLock lock = new ReentrantLock;
>  for (int i=0; i < 4; i++) {
>    t[i] = new Thread(
>      delegate int() {
>        go.wait(); // wait for signal from main thread
>        // ... do something interesting ...
>        lock.lock();
>        total += 100;
> for(int k=0;k<1000000;k++) { } // seems to need a pause?
>        lock.unlock();
>        allDone.countDown();
>        return 0;
>      });
>    t[i].start();
>  }
>  go.countDown(); // let worker threads go
>  allDone.wait(); // wait for all workers to finish
>  printf("%d\n",total); // total should now be 400
>  return 0;
>}

After a bit more experimenting it seems like a volatile in place of the for loop will also make it work

        lock.lock();
        total += 100;
        volatile lock.unlock();

Without the loop or volatile I get seg-v's on the unlock. Probably the loop was just preventing some reordering optimization. I haven't looked at the disassembly to see exactly what happened.

-Ben