• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Another Threading Issue
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Another Threading Issue


  • Subject: Re: Another Threading Issue
  • From: Philippe Wicker <email@hidden>
  • Date: Wed, 17 Dec 2003 22:20:22 +0100

On Wednesday, December 17, 2003, at 08:05 PM, Jeremy Jurksztowicz wrote:

I had a similar problem to solve a few times ago. A bunch of variables had to be updated as a result of some user commands and this update had to be synchronized with the rendering thread. The solution was to use a non blocking FIFO. Data to atomically update are pushed - as one block of data - by the main thread into the FIFO, and pulled out by the render thread at the beginning of each render cycle. I don't know wether this approach fits your needs or not. As far as I have understood, the fifo::push should be called in setEnv1, and the fifo::pull in pullDataStream. Using this method, you don't need anymore to lock the sharedMutex.

A non blocking fifo is not very complicated to design. I have my own code (a C++ class) that I can provide you if you wish. Another alternative is to look in the list archive for a Bill Stewart posting about a queue to push midi notes (sorry, I don't remember the exact subject). The queue code was targeted at MIDI notes exchange but can easily be modified to fit general needs.


I hate to beat a dead horse but...
I have recently ported a windows app to CoreAudio, using the HAL.
My audio supplier class provides PCM wave data from a buffer stored on memory. The way the data is provided to
the IO proc depends on parameters in the class instance of course. In the windows code I was doing something like this:

class Provider {
Envelope * env1;
float data1;
// ... Many more variables ...
public:
void pullDataStream (float ** buffs, unsigned int frames, unsigned int channels) {
Lock lck(sharedMutex);
if(data1 => somethingOrOther)
doThisOrThat();
// ... Get all the data ...
env1->applySectionAndIncrement(buffs,frames,channels);
lck.unlock();
}
void setEnv1 (Envelope* env) {
Lock lck(sharedMutex);
delete env1;
env1 = env;
if(env1) env1->syncronizeWithThis(this); // Complex method to make sure the envelope is synced.
}
// Blah, Blah, Blah, you get the idea...
};

While this code worked, and still works just fine, I keep seeing posts about how no blocking calls should be made in the
IO proc, including memory allocations and THREAD LOCKS. Seeing as I have to pass data to the io thread while it is running,
how do I get it there without locking? So of course I did an exhaustive search of the mailing list archives, and lo and behold
I get all sorts of stuff on the circular buffer. Great!

BUT! As you can see in the example above, In the protected section of setEnv() there is more than just a parameter assignment,
there is also some complex code to sync the param (in this case an envelope) with the rest of the classes sound data. This code
must either:
1-Run in a protected block on the main thread.
2-Run in the IO thread each and every cycle of getting audio data!

The reason behind 2 is that if I can atomicaly change the envelope parameter, It does me no good (rather harmful, really) if it is
not synced up before ANY MORE audio data is processed. Sure I could put another member, env1DidChange of boolean type,
and update that as well, but what if the envelope is required between calls to set it and it's boolean changed flag?

This is an artificial example, but this pattern of behavior is very common to this class, which can do some wonderful things
because it handles such high level abstractions such as Envelopes, Filters, etc... rather than having all its parameters low
level floating point primitives.

So my first idea was to change my provider class to an AudioUnit, they provide auto synchronization... right? ... Right?!
I looked up and down in the AUBase class to see if there was thread syncing, and eureka! I see something about an
AUElement class, and getting parameters, and AHA! In the AUBase class there is SafeGetElement()! To my disappointment
this has nothing to do with thread safety (or did I miss something?). So perhaps some example AudioUnit code will tell me
what I need to know...? No thread syncing in ANY example code I have downloaded...

So, here are my questions:
1. If I implement audio units to specification, do I have to implement any thread safety measures if it will only be accessed by the
IO thread AND the main thread. If no syncing is needed, should I only access my AU through the C AudioUnits API, or can I safely
call its class methods directly? (from the AUBase source code this seems unlikely)
2. If I decide not to implement an AU and reuse my provider class, would it be reasonably good practice to pull its audio data in a
feeder thread, locking to my hearts content (only one lock per IO cylcle is required), and pumping the data through a circular buffer
to the high priority IO thread?

I know that threading issues are common on this list, and am sorry If my late night archive browsing missed the obvious answers.
Thank you for your help.

Jeremy Jurksztowicz
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.


Philippe Wicker
email@hidden
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.

References: 
 >Another Threading Issue (From: Jeremy Jurksztowicz <email@hidden>)

  • Prev by Date: Re: QT 6.4, CoreAudio and USB devices
  • Next by Date: What exception to launch when AudioConverterDataSupplier fails?
  • Previous by thread: Another Threading Issue
  • Next by thread: What exception to launch when AudioConverterDataSupplier fails?
  • Index(es):
    • Date
    • Thread