To summarize then –
Scztt was correct to point out that thisThread won’t work in your case, because the onFree function runs outside of the routine. (I missed that.) Also the recommendations about while loops are on point, for a task that should run until xxx condition fails.
If you’d like to use a thread reference, it’s likely to be more reliable to save your own reference than to rely on magic variables. (The magic variable thisThread is necessary in the class library, where some methods need to access properties of the currently running thread.) There is a part of your code that knows which Routine to stop – the part that’s calling fork
:
(
var thread;
thread = {
20.do {
var synth = {SinOsc.ar(1.0.rand.linexp(0, 1, 440, 880), mul:0.1)}.play;
synth.onFree { thread.stop };
1.0.yield;
}
}.fork;
)
… for a least-intrusive edit.
Task is the reason why threadPlayer was introduced, though – “CondVar
internally uses thisThread.threadPlayer
to store the currently playing thread in a list” precisely because if it didn’t, there would be no way to signal a Task and thus no way to control it through the Task interface after it was paused and signaled. (The online documentation, from 3.12.2, still says Task doesn’t work with Condition [and by extension, CondVar]. threadPlayer
is the fix for that.)
For the “parent routine” case, when possible I’d prefer to keep the reference myself, because I know which Routine I’d like to stop, and there’s a clear part of the code that has access to it. Better to store the reference explicitly so that readers can see the intention in the code.
E.g. here:
As noted, you’re not necessarily sure how far up the chain the threadPlayer will be, so, in the specific case, I think it may be clearer to grab it yourself:
(
var threadToBeStoppedLater = fork {
var inner = Routine {
Or even:
(
fork {
var threadToBeStoppedLater = thisThread;
var inner = Routine {
(FWIW in that example, I’d also avoid mixing the Routine-as-scheduled-action idiom with the Routine-as-data-stream idiom – personal opinion, no problem if others disagree, but IMO the inner routine is yielding data, not waiting, and there’s not a strong reason to put the OSCFunc inside it. Clarifying the code also removes the need for threadPlayer then
)
hjh