www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Thread questions

reply novice <novice_member pathlink.com> writes:
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!
Oct 06 2004
parent reply Ben Hinkle <bhinkle4 juno.com> writes:
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!

Oct 07 2004
parent reply novice <novice_member pathlink.com> writes:
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.

:)
Oct 07 2004
next sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"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
Oct 07 2004
next sibling parent "Ben Hinkle" <bhinkle mathworks.com> writes:
 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; }
Oct 07 2004
prev sibling parent Ben Hinkle <bhinkle4 juno.com> writes:
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
Oct 09 2004
prev sibling parent reply Burton Radons <burton-radons smocky.com> writes:
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.
Oct 07 2004
parent reply Sjoerd van Leent <svanleent wanadoo.nl> writes:
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
Oct 07 2004
parent reply Sean Kelly <sean f4.ca> writes:
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
Oct 07 2004
parent Sjoerd van Leent <svanleent wanadoo.nl> writes:
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
Oct 07 2004