Thread overview
spawn and wait
Jul 03, 2014
Puming
Jul 03, 2014
Ali Çehreli
Jul 03, 2014
Bienlein
Jul 03, 2014
Sean Kelly
Jul 03, 2014
Puming
Jul 03, 2014
Ali Çehreli
July 03, 2014
Hi,

I want to spawn several similar tasks and then wait for all of them to complete to go on do some other things, like:

```d
void task(int id)
{
  // do the stuff
}

void main()
{
  foreach (i; 0..10) {
    spawn(&task, i);
  }
  wait(?); // wait for all task to complete
  doSomeOtherThings();
}
```

But I don't see a `wait` method for Tid, similar to Pid in std.process.

What is the idiomatic way to do these things?

My current workaround is using messages:

```d
#!/usr/bin/rdmd
import std.stdio;
import std.concurrency;

void child(int id)
{
	writeln("Starting child: ", id);
	ownerTid.send(id);
}

void main()
{
	foreach (i; 0..10)
	{
		spawn(&child, i);
	}
	for (int n = 0; n < 10; ++n) {
		receive((int i) {
			writeln("Received:", i);
		});
	}
}
```

But it is verbose and seems error prone.
July 03, 2014
On 07/02/2014 08:29 PM, Puming wrote:

> I want to spawn several similar tasks and then wait for all of them to
> complete to go on do some other things

If you don't care about account for each of them individually, core.thread.thread_joinAll would work. The following program starts two waves of threads and waits for both of the waves to complete:

import std.stdio;
import std.concurrency;
import core.thread;

void foo(Duration duration)
{
    writefln("Working for %s", duration);
    Thread.sleep(duration);
}

void spawnThreads(size_t count)
{
    foreach (i; 0 .. count) {
        spawn(&foo, (i + 1).seconds);
    }
    writefln("Started %s workers", count);
}

void main()
{
    spawnThreads(2);
    writefln("Waiting for all to finish");
    thread_joinAll();

    spawnThreads(3);
    writefln("Waiting for all to finish");
    thread_joinAll();
}

Ali

July 03, 2014
There is also a Semaphore and Barrier class:

http://dlang.org/phobos/core_sync_barrier.html
http://dlang.org/phobos/core_sync_semaphore.html
July 03, 2014
On Thursday, 3 July 2014 at 04:51:07 UTC, Ali Çehreli wrote:
> On 07/02/2014 08:29 PM, Puming wrote:
>
> > I want to spawn several similar tasks and then wait for all
> of them to
> > complete to go on do some other things
>
> If you don't care about account for each of them individually, core.thread.thread_joinAll would work. The following program starts two waves of threads and waits for both of the waves to complete:
>
> import std.stdio;
> import std.concurrency;
> import core.thread;
>
> void foo(Duration duration)
> {
>     writefln("Working for %s", duration);
>     Thread.sleep(duration);
> }
>
> void spawnThreads(size_t count)
> {
>     foreach (i; 0 .. count) {
>         spawn(&foo, (i + 1).seconds);
>     }
>     writefln("Started %s workers", count);
> }
>
> void main()
> {
>     spawnThreads(2);
>     writefln("Waiting for all to finish");
>     thread_joinAll();
>
>     spawnThreads(3);
>     writefln("Waiting for all to finish");
>     thread_joinAll();
> }
>
> Ali

Thanks that is what I'm looking for
July 03, 2014
On 07/02/2014 08:29 PM, Puming wrote:

> I want to spawn several similar tasks and then wait for all of them to
> complete to go on do some other things, like:

[...]

> My current workaround is using messages:

I forgot to mention that if message passing is merely a "workaround" :) in this case then perhaps std.parallelism is more suitable.

For example, your code may be as simple as running a loop in .parallel in a foreach loop. The foreach loop would not advance until all of the parallel tasks have been completed:

import std.stdio;
import std.parallelism;
import std.range;

void task(size_t id)
{
    writefln("Working for %s", id);
}

void main()
{
    foreach (id; iota(10).parallel) {
        task(id);
    }

    writeln("All done");
}

Ali

July 03, 2014
On Thursday, 3 July 2014 at 10:25:41 UTC, Bienlein wrote:
> There is also a Semaphore and Barrier class:
>
> http://dlang.org/phobos/core_sync_barrier.html
> http://dlang.org/phobos/core_sync_semaphore.html

This is probably what I'd do, though both this and thread_joinAll
will only work if you have one kernel thread per spawn.  If
you're using a fiber-based Scheduler, this won't work as
expected.  In that case you might want to use spawnLinked and
trap the LinkTerminated messages or something like that.