Stopping all Tasks? Starting a Task multiple times?

Hi list,

I am wondering if there is a thing such as Group but for Tasks? In a
composition I am using multiple tasks in parallel and sometimes would
like to stop them all without issuing a Ctl-.
Is there a way?

Furthermore, I know that the advantage of a Task is, that it can’t be
started multiple times. How would I proceed if I wanted to?

Perhaps there is a common solution to these two questions. Something
like a Dictionary for Tasks? Has anyone already found a solution?

cheers,
Peter

In a way, there is: it’s called an Array.

var groupOfTasks = [
	Task {

	},
	Task {

	},
	...
];

groupOfTasks.do(_.play(...));

groupOfTasks.do(_.stop);

Or:

var taskList;

Tdef(\aTask, {  });

Tdef(\anotherTask, {  });

taskList = [\aTask, \anotherTask];

taskList.do { |name| Tdef(name).play(...) };

taskList.do { |name| Tdef(name).stop };

Synths need Groups because they live in the server.

Tasks are language-side objects. Because they live in the language, they can be placed into any language-side collection object. So it isn’t necessary to provide a special-purpose task-collection, because general-purpose “store anything” collections already exist. (Like, you said “Dictionary for Tasks” – do you imagine that something prevents you from putting Tasks into a Dictionary? There is no such rule… you had the solution right in front of your eyes :wink: )

The reason why Tasks don’t allow multiple starts is because starting the same thread multiple times doesn’t work the way that you probably expect.

You can multiple-schedule a Routine. So let’s see what happens in that case. We’ll run a one-second thread twice, once on the beat and once at 0.5 sec.

(
r = Routine {
	inf.do { |count|
		"Time = %, count = %\n".postf(
			thisThread.clock.beats,
			count.asInteger
		);
		1.0.wait;
	}
};
)

(
// the "0.5" thing ends up being messy
// so this is rather more complicated to schedule than I'd like
// but, no choice...
Routine {
	r.play(quant: 1);  // next beat
	r.play(quant: [1, 0.5]);  // 0.5 beat later than next beat
}.play(quant: 1);
)

Time = 120.0, count = 0
Time = 120.5, count = 1
Time = 121.0, count = 2
Time = 121.5, count = 3
Time = 122.0, count = 4
Time = 122.5, count = 5
Time = 123.0, count = 6

r.stop;

I think most users would think, “I played the routine twice, and those should be in parallel: 120 and 120.5 both at count 0, 121 and 121.5 both at count 1.” But this isn’t what happens. There is only one thread, so the count values end up being interleaved between the multiple occurrences.

The Task restriction is to prevent you from making this mistake.

So, before discussing how to overcome that restriction, we should be absolutely sure that the mistake is what you want. (And, if it isn’t what you want, then the code you need is different from “run the same task multiple times.”)

hjh

Thanks James,

your proposed solutions are very elegant. Suppose I have kept references
to running tasks in environment variables that have a common string in
their names (eg. ~myTask1, ~myTask2, …) is there an easy way to send
the .stop method to all of them by some means of a wildcard? I imagine
~myTask*.stop
or in pseudo code:
queryAllEnvVars | grep myTask | .stop ?
Thanks again,
Peter

Highly recommended to avoid this usage pattern, and use arrays instead.

hjh