Re: Coreaudio-api Digest, Vol 3, Issue 127
Re: Coreaudio-api Digest, Vol 3, Issue 127
- Subject: Re: Coreaudio-api Digest, Vol 3, Issue 127
- From: George Warner <email@hidden>
- Date: Mon, 24 Apr 2006 08:38:54 -0700
- Thread-topic: Coreaudio-api Digest, Vol 3, Issue 127
on 4/24/06 6:30 AM, email@hidden at
<email@hidden> wrote:
> Apologies if this is not the right list, but someone at carbon-dev suggested
> I ask here, as this list deals with music processing apps a lot.
I hate to bounce you to yet another list but the one most likely to help you
is probably the MT/SMP ( multitasking / symmetric multiprocessing) list:
Send Mt-smp mailing list submissions to
email@hidden
To subscribe or unsubscribe via the World Wide Web, visit
http://lists.apple.com/mailman/listinfo/mt-smp
or, via email, send a message with subject or body 'help' to
email@hidden
You can reach the person managing the list at
email@hidden
> There is a 1 ms callback installed as a Timer function (i.e. using
> NewTimerUPP() and InsXTime()). So I'm getting 1ms interrupts, and having it
> process a list of queued tasks stored in a linked list according to
> execution time (the "ScheduledQueue") - for my purposes, this is used to
> generate MIDI data in real-time to create algorithmic music. (I guess this
> is what is known as a preemptive thread?)
More or less. These "old school" timers API have been depreciated. These
days I'd write this as an MP task (see <Multiprocessing.h>) with a loop that
has a 1 mSec delay in it:
static OSStatus MyMPTask(void* pParam)
{
AbsoluteTime tNextAbsTime = UpTime();
Duration animationDelay = 1 * durationMillisecond; // 1000 cps
while (gLoop) {
tNextAbsTime = AddDurationToAbsolute(animationDelay, tNextAbsTime);
process_queued_tasks(); // your code here!
MPDelayUntil(&tNextAbsTime);
}
return noErr;
}
Note that the next time is computed before the process_queued_tasks routine
is called. This is so that the amount of time that the routine takes won't
effect the overall loop time (unless it takes more than 1 mSec).
The following code is used to start the thread.
MPTaskID tMPTaskID;
OSStatus error = MPCreateTask( MyMPTask, NULL,
16384, kInvalidID, NULL, NULL, 0, &tMPTaskID);
if (noErr != error)
printf("\nMPCreateTask error: %ld.", error);
FYI: When these MP API's were introduced (in Mac OS 8.6) we already had a
(cooperative) thread manager. In order to avoid confusion with that we
called these preemptive threads "tasks". Which unfortunately is the same
term that *NIX systems used to refer to what in Carbon land we referred to
as processes.
> There's another queue of tasks, the "DeferredQueue", that is *NOT* performed
> at interrupt level, such as redrawing blinking leds, GUI updating, etc. This
> tasklist is processed by the app's "idle time" mechanism, whenever it's not
> busy. (I guess this is the main app thread?) I can find nothing in
> PowerPlant related to threading, so I guess it's just one thread within the
> main event loop, i.e. LApplication::Run()).
There are several different ways to handle this. You can ether use a Carbon
Event timer to occasionally check the queue to see if there's anything for
it to do; Or you could have your thread send a custom Carbon Event to the
main thread to tell it to check the queue; Or you could send one of the
standard Carbon Events to tell a control or HIView to update itself. (Or you
could do any and/or all combinations of the above depending on your needs.)
> There is a mechanism to set a "lockoutFlag" around "critical sections" of
> code that you don't want interrupted for any reason. The lockout flag
> prevents interrupts while it is set to true. Both types of functions
> above are able to set and unset this flag, referring of course to the
> previous state when setting and unsetting.
>
> In OSX, it appears that sometimes, this flag is getting stuck in the locked
> position, at which point the execution of the music generation stops.
Sounds to me like this lock is not a thread-safe lock. You should probably
consider switching to a real critical region, semaphore or mutex.
> My guess is that the execution of the DeferredQueue that handles GUI
> updating etc. (the main app thread) is able to be interrupted by the Mac OSX
> at any time (in a different way than what happens on OS9). So the main
> thread apparently suspends activity while in the middle of redrawing, leaves
> the lockoutFlag set to true, and then the interrupt level thread cannot
> perform any more tasks. And the status of the flag somehow gets confused. Or
> something like that. Or maybe not.
In Mac OS 9 those interrupt timers effectively disabled interrupts until the
callback routine completed and returned. You could more-or-less assume that
they would run to completion so you didn't have to code any more elaborate
locks. On Mac OS X these are implemented in threads that can be preempted
before completion. So you have to use real atomic locks.
> 1. Does anybody know what I'm talking about? ;-)
No... ;-)
> 2. I don't even know what kind of threading this is, now that its on Mach-O.
> I don't see "NewThread" being called anywhere in PowerPlant, and the only
> thing I'm doing is installing the TimerProc. I've tried reading the
> technote2028 that compares OS9 and OSX threading, and it's a pretty high
> level of greek (or is that geek) to me. Same with the Thread Manager
> reference. I'm not even sure what level of threading/tasking I was using, or
> now am using since I ported my app to mach-O. I never really worried about
> it much before. It just worked. ;-)
The original (cooperative) thread manager (and timer services for that
matter) is still around and has its uses but for the most part you would
probably be best served by the MP API's. The POSIX (pthread) API's have a
much steeper required learning curve. If your interested in Cocoa the
NSThread is the way to go.
> 3. On another front, I see that this whole method of doing things has been
> deprecated (or has it?). The Time Manager Reference says "Deprecated. Use
> Carbon Event Loop timers or Cocoa NSTimers instead." I was checking out the
> discussion of "InstallEventLoopTimer()" - is this going to have the same 1ms
> accuracy as the other way of doing it? The Carbon Event Manager Reference
> says about it "IT executes at task level and should not be confused with
> Time Manager tasks or any other interrupt-level callback." I'm confused
> about what I need to do here...
The Carbon Event loop is at the mercy of the handlers that it calls. It
can't process the next event until the current handler being called finishes
its task and returns. If that's ten seconds or ten years there's nothing
that it can do about it. It's up to the developers to move tasks that block
the event loop off the main thread to avoid neglecting the event queue.
> I'd prefer to rewrite as little of this as possible. It almost works, except
> for this lockout flag getting "stuck".
My guess is that the least amount of work would be to switch to using a real
thread safe lock (like a semaphore) or a critical region. The
Multiprocessing API's also include a thread safe queue (FIFO). If that's
what you're trying to protect with the lock then you could switch to MP
queue and eliminate the lock altogether. ;-)
--
Enjoy,
George Warner,
Schizophrenic Optimization Scientist
Apple Developer Technical Support (DTS)
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden