discuss-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Discuss-gnuradio] Thread-Safe Blocking?


From: Michael Dickens
Subject: Re: [Discuss-gnuradio] Thread-Safe Blocking?
Date: Sun, 18 Dec 2005 14:46:17 -0500

Sorry for the delayed reply; just not enough time in the day.

1) On Dec 17, 2005, at 10:28 AM, Robert McGwier wrote:
I think the question was probably more than "what tools" but I could be wrong.

No, I had gotten to the point where "what tools" was all I was looking for. But your reply let me know that my most-self-determined understanding was correct.

2) On Dec 17, 2005, at 12:28 PM, Robert McGwier wrote:
direction is release from gr-audio-osx using semaphores, flags, etc. but never does it by releasing a mutex which has been acquired by gr since they [do] (and will) block the audio callback. If the data is not ready for the audio callback, issue an error and fill in the buffers with zeros, the last data, whatever.

The only time gr-audio-osx truly blocks ("waits for data") is in the "source" in "work":

On Nov 27, 2005, at 6:24 PM, Eric Blossom wrote:
(1) An audio source should block until it can return some non-zero
amount of data from the underlying audio interface.  If it asks for
1024 samples and it gets 64 samples, it should return after the 64
samples, not reissue a blocking call for the remaining 1024-64
samples.

Otherwise, there is no "waiting for data" type of blocking. The semaphores are used only to keep the various threads from stepping on each others toes. Here is a little more info:

3) This all started in the "sink", where CoreAudio (CA) uses a thread and "pulls" data from a callback (which I create), while GR uses a thread to "push" data to the code I write. Somehow these need to talk to one another, and the fastest way (within the limits of the GR programming model and languages and such) is a ring buffer that can be accessed by both threads. The scenario is similar with the "source", where CA issues a callback indicating that data from the input device is ready to be read; this callback reads the data, converts it to what GR needs, then drops it into another ring buffer to be read by GR's callback "work".

The primary problem I was having was that, as I cannot control context switching between threads, it could happen that a variable would be in the process of being written to by both threads at the same time. This happened very infrequently, but when it did it would lead to a buffer underrun (meaning that the code thought there was more data but there really wasn't).

There was only 1 variable to which this was happening where I could "see" it (a counter with the current total number of samples stored in the buffers), but it was clear that I needed a thread-safe blocking mechanism ... so I asked the question and got the answer quickly "onmi_semaphores". I implemented those semaphores for both source and sink, and that took care of the issue. My particular implementation is very simple for both "sink" and "source": it waits () at the start of "work" and posts() at the end, and likewise waits () at the start of the CoreAudio callback and posts() at the end. At least for audio up to 50 kHz sample rate, this does not seem to cause any significant issues when feeding either CoreAudio or GR.

For "sink", "work" just copies the buffer then returns, and the CA callback just takes the copied "work" buffer, copies it to the CA buffer then returns. On this side, the semaphores cause very little in the way of increased latency or decreased throughput; while another implementation might be "better", this one works just fine for now.

For "source", the CA callback has to get the data from the input device, convert the data to GR's wants, and copy the output to the ring buffer. "work" blocks until is has data to return (per Eric's directive above; releasing the semaphore while blocking to allow for data to come in from the CA callback) by copying from the ring buffer to the output variable. On this side, there is probably a more efficient way to do the semaphores, but what I have works ... and that's a good place to start!

What I need to do is to pick through the code and determine how to better implement the semaphores in order to reduce latency and/or improve throughput, or just to have cleaner code. One option - and probably the one which makes the most sense - is to augment my ring buffer to the thread-safe (via internal semaphore use), and remove the semaphores from my code. This would benefit both the "source" and "sink", so it's something I might experiment with.

So another question: Does GR have its own ring buffer that is thread- safe? If so, I'd prefer to use that one rather than muck with my own code (no matter how simple or not it might be; why reinvent the wheel every time, no?).




reply via email to

[Prev in Thread] Current Thread [Next in Thread]