[chuck-users] Why do child shreds get killed?
Manfred Brockhaus
manfred.brockhaus at chello.at
Tue Sep 6 15:16:18 EDT 2005
Here is a quote from the language specification:
"in the current implementation, when a parent shred exits, all child
shreds all exit (this behavior will be enhanced in the future.)"
So obviously the developers are aware of the problem. I agree that the
current behavior is quite inconvenient, at least for traditional
programming (as opposed to on-the-fly).
-mb
On Sep 6, 2005, at 6:53 PM, Robin Davies wrote:
> Currently, if a shred terminates, all of its child shreds get
> terminated as well.
>
> This raises the following interesting question: why?
>
> Honestly, from a user’s perspective, I can’t think of a compelling use
> of this feature. Whether there are internal implementation issues that
> motivate this feature or not is a separate question, I guess; but I
> can’t really think of a good reason to terminate child shreds from an
> implementation perspective, either. (Unless you’re relying on shred
> termination to garbage collect).
>
> On the other hand, I can think of very compelling reasons why shreds
> should not outlive their parents.
>
> I’ve been bitten by this several times – by shreds silently being
> terminated because parent shreds have terminated.
>
> Here’s my compelling use case for allowing shreds to outlive their
> parents.
>
> I spent the weekend playing with chuck. With audio languages (CSound,
> SAOL, Music-N, &c), one of the constant challenges is how to provide
> clean and modular integration between expensive control-rate
> operations, fast audio-rate operations, and external events.
>
> Having had exposure to MusicN based languages that provide
> control-rate processing, I thought I’d try using the control concept
> in chuck.
>
> Here’s the theory: write an IInstrument abstract class that provides
> an abstract Tick() method which gets called at control-rate. Output of
> the instrument is placed on the Instrument.Out ugen so that
> instruments can then be routed onto an external output.
> Implementations of IInstrument then call (for example)
> StartTick(16::samp), which causes the Tick method to be called every
> 16 samples on a separate shred. This works very well. The end result:
> an AnalogSynth class, implementing IInstrument, that provides two two
> control-rate lfos, two control-rate envelopes, one band-limited
> oscillator ugen (private build coming to a Chuck near you soon) and a
> filter ugen. AnalogSynth runs about 12 voices in realtime on my lowly
> 800Mhz home machine, without any real attention to optimization! So
> far so good. The purpose of the Tick() processing is,of course, to
> run the LFOs and ADSrs at reduced rate (every 16 samples), and then
> perform all of the expensive routing of lfos and ADSrs outputs onto
> UGens at something less than audio rate.
>
> Well. It does work very well, as long as I drive the IInstrument from
> midi or OSC input. It fails spectacularly if notes are triggered from
> temporary shreds when writing scores in Chuck. Consider the following:
>
> function void PlayNote(IInstrument instr, float midNote, dur length)
> {
> instr.NoteOn(midiNote,1.0);
> length => now;
> instr.NoteOff(midiNote);
> }
>
> spork ~ PlayNote(analogSynth, Midi.C4, 1.5::beat);
>
> This fails, spectacularly. Internally, the Tick shred gets started up,
> but it shuts down as soon as the PlayNote shred terminates (causing
> the note to get stuck).
>
> In retrospect, I guess the answer is to create a tick shred at the
> time the instrument is created, and then use events to synchronize the
> tick shred. But that’s just so… so… inconvenient. Or another approach:
> make PlayNote wait forever, after the note off. But that’s just so…
> so…. ugly. Hmm. Or maybe a WaitForAllChildThreadsToDie() function.
>
> The event solution also runs into significant problems with
> controlling the first tick after startup. Consider: An IInstrument
> receives a note-on event. It initializes all of it’s control rate
> state variables (reseting ADSRs, for example). Now it needs to start
> the tick shred up. So it signals an event. The question is this: will
> the tick shred run in the current cycle or not? If it doesn’t then
> StartTick() should call IInstrument.Tick(). But whether the shred ran
> in the current thread or not is non-deterministic. It depends on
> whether the shreduler ran the current thread or the tick thread first
> for the current value of Now. Even worse. The tick shred can no longer
> perform “16::samp => now”, because the noteon event may have arrived
> at some non-modulo-8 mutiple of now::samp. So this approach requires
> complicated and expensive handshaking between the Instrument and its
> tick thread to get everything lined up and operating
> deterministically. (<thinking>… this is doable, and probably the way
> I’ll go)
>
> Or another use-case for the same:
>
> function void PlayTheWholeSong()
> {
> Spork ~ PlayBassMotif1();
> Spork ~ PlayMelody1();
> 12::beat => now;
> Spork ~ PlayBassMotif1();
> Spork ~ PlayMelody2();
>
> // oops. No more bass motif or melody shred.
> }
>
> The feature request; maybe a way to let shreds re-assign their parent
> shred to the root shred. That would be nice. Or maybe just don’t
> terminate child shreds at all.
>
>
>
> Robin Davies
> Lead Software Developer
> Quest Web Reports
> Quest Software
> 613.270.1569
>
> Identity Management for the Windows Enterprise: See how Quest helps
> you leverage your existing investment to solve the identity management
> challenge!
>
> _______________________________________________
> chuck-users mailing list
> chuck-users at lists.cs.princeton.edu
> https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
More information about the chuck-users
mailing list