Re: AU Threading Question
Re: AU Threading Question
- Subject: Re: AU Threading Question
- From: Gregory Wieber <email@hidden>
- Date: Fri, 08 Apr 2011 13:51:16 -0700
Hi Stephen,
Sure -- if somehow the GUI and the glitches and your audio are related, you might be somehow updating your GUI from your audio thread. You probably have already made sure this isn't the case, but I've noticed before in my own code that I had overlooked areas where that was not the case. I don't have the reference in front of me, but apple emphasizes that GUI stuff should always be called on the main thread.
My hunch is that it's not the GUI though, and probably something else that happens when you do a touch event (maybe you're creating arrays, passing lots of stuff around, etc) and it's affecting BOTH the GUI and the audio, which is why you're noticing it. Hope that helps, if vague.
best,
Gregory
On Fri, Apr 8, 2011 at 1:16 PM, Stephen Blinkhorn
<email@hidden> wrote:
Hi Gregory,
On 8 Apr 2011, at 11:22, Gregory Wieber wrote:
Not sure if you're aware, but the GUI stuff should ALWAYS run from the main thread.
Could you expand on this a little?
Stephen
On Fri, Apr 8, 2011 at 10:03 AM, Stephen Blinkhorn <email@hidden> wrote:
Thanks for your comprehensive answer Brian.
On 8 Apr 2011, at 02:54, Brian Willoughby wrote:
Or is it possible that the Render method will have to wait for the GetProperty()read to finish before writing new values?
As far as the processor is concerned, the entire array is just separate memory locations that can be read or written in any order at any time, and threading will allow them to be written by one thread in the middle of being read by another thread. In other words, nothing is going to automatically make the Render thread stop while some other thread is reading these values. No part of the code is aware of the special purpose of these memory locations, or the tie-in between the writer (producer) and reader (consumer). You, as the programmer, must establish the rules and enforce them.
OK, that's what I was asking really.
I would like to ask you to step back for a moment and consider what your program is doing, as designed at the moment.
It appears that you are updating the peak meter levels on every Render call (or at least you haven't specified any mechanism in your code to limit how frequently these values are updated). With typical buffer sizes, this represents an update rate of maybe 10 times per second (4096 frames per buffer @ 44,100 frames per second) to as high as maybe 345 times per second (128 frames per buffer @ 44,100 frames per second). With low latency and high sample rates, which are quite popular these days, you could easily have hundreds or thousands of updates per second.
At the same time, you have an NSTimer polling your data - hopefully at a more sensible rate like 24 Hz or so, certainly less than 60 Hz at the most. But that NSTimer is not synchronized with the Render updates, and if your Render thread is updating the values hundreds or thousands of times per second it's highly likely that an update will change part of the array in the middle of your Cocoa view copying the values. This is a textbook example of a race condition.
A better approach would be to reduce the update rate so that it is as slow as the display rate, and then you'd have much less likelihood of hitting that race condition. Also, instead of polling the data for changes at a rate that is not synchronized to the updates, why not just have the Render thread tell the Cocoa view that something has changed? This avoids polling entirely, and should eliminate the race condition unless the Cocoa view is so slow to respond that it catches the next update (if your Cocoa view is too slow to keep up, then you should slow the update rate anyway).
The Render thread updates the peak meter values at the same refresh rate as the GUI (which as you pointed out is usually several or more blocks of data) so it stores peak values across render calls until it knows what the real peak value is. At the same time I set/unset a flag so that the render method can see if a GUI read has occurred and the GUI can ascertain if there is fresh data to display. So it's all in sync.
I don't really like the NSTimer approach and I did switch to using a PropertyChanged mechanism at one point but the overall effect wasn't as 'smooth' from the user's point of view. I might try that again quickly as on paper it seems like a better approach.
My apologies if I misunderstood your question or if you already knew all of this.
No apology required Brian, many thanks for the answers!
My main concern is that I'm experiencing occasional audio glitches and stuttering (although no one else has ever complained about this). I've taken care to make sure I'm not doing any memory allocation via malloc or new during render calls (I use placement new using a preallocated memory block) but I've noticed that the GUI also tends to 'hang' during these periods of glitching/stuttering and I'll get a CPU spike.
So the reason I asked the original question was to get a better understanding of how threading works in an audiounit/host context and to make sure that I'm not doing anything via the GUI that could cause the Render thread to block.
To confirm I'm not totally off the mark; When the GUI thread calls GetProperty() the GetProperty() call is executed on the GUI thread and in my case accesses data shared between threads? Is that correct?
Thanks,
Stephen
Brian Willoughby
Sound Consulting
_______________________________________________
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
_______________________________________________
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
_______________________________________________
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