[LAD] Realtime inter-thread communication

From: Sebastian Gesemann <s.gesemann@email-addr-hidden>
Date: Tue Mar 01 2016 - 19:09:35 EET

On Tue, Mar 1, 2016 at 4:54 PM, Paul Davis <paul@email-addr-hidden> wrote:
> On Tue, Mar 1, 2016 at 10:12 AM, Sebastian Gesemann <s.gesemann@email-addr-hidden>
> wrote:
>>
>> Thank you all for the responses!
>>
>> On Mon, Feb 29, 2016 at 9:05 PM, Harry van Haaren <harryhaaren@email-addr-hidden>
>> wrote:
>> > On Mon, Feb 29, 2016 at 7:52 PM, Spencer Jackson <ssjackson71@email-addr-hidden>
>> > wrote:
>> >> > The generic solution for cases like this is a lock-free ringbuffer.
>> >> I've also used the jack ringbuffer for this and it was easy enough.
>> >
>> > Simple tutorial on using JACK ringbuffer and C++ event class here:
>> > https://github.com/harryhaaren/realtimeAudioThreading
>>
>> I've looked into JACK's ringbuffer implementation. It doesn't look too
>> complicated. Thank you all for suggesting it! But I'm a little bit
>> concerned about ISO standard compliance. According to the
>> multi-threading-aware update to the C11 and C++11 memory models, the
>> access to the ringbuffer's data (*buf) is technically a data race and
>> therefore invokes undefined behaviour. Only read_ptr/write_ptr are
>> somewhat protected (volatile). From what I understand, given the
>> C11/C++11 memory model, one is supposed to use "atomics" for all
>> read/write accesses in such situations (including *buf). But so far, I
>> havn't gathered much experience in this kind of lock-free programming.
>
> Sadly, you still don't understand how a lock-free ringbuffer works.

Oh, don't be sad. I'm sure you're underestimating my understanding of the topic.

> The key insight to have is this:
>
> * the calculation of what can be read and what can be written may, in
> fact
> be incorrect due to threading
>
> BUT
>
> they are ALWAYS wrong in the "safe" direction. if the calculation is
> wrong
> it will ALWAYS underestimate data-to-be-read and space-to-be-written.

I understand that.

> that is: you will never attempt to read data that should not be read, and
> you will never attempt to write to space that should not be written. This is
> true of ALL lock-free ringbuffer designs, not just JACK's. The property
> arises from the requirement that they are single-reader/single-writer. If
> you violate this (e.g. attempt to move the read-ptr from the write thread or
> vice versa), then all bets are off unless you use some higher level mutual
> exclusion logic (which has no place in the ringbuffer itself. The design
> works because in audio contexts, when you use a ringbuffer, you are more or
> less guaranteed to be using a design where you keep reading and keep writing
> to the ringbuffer over and over. The design cannot work for single-shot
> communication where you must always collect ALL possible data in a
> thread-synchronous fashion. This is not the case for audio work.

I understand that. So far, nothing you said was new to me.

> Now, that said, there are some under-the-hood issues with the actual JACK
> ringbuffer code, but they have absolutely nothing to do with the high level
> semantics, and that is what you're relying on. Those issues concern the use
> of memory barriers, and are thus related to code-reordering not to
> atomicity.

It depends on what meanings you attach to the words "atomics" and
"atomicity". I was trying to use the term "atomic" in a way consistent
with the C11/C++11 memory model. In this context, atomicity is not
only about having logically multiple operations done as a single one
(fetch-and-add, compare-and-swap, etc) but it also involves memory
ordering hints (defaulting to sequential constistency but weaker
models are possible). So, it seems to me that you were not familiar
with this. I said I have little experience with lock-free programming
but that does not mean I'm completely unaware of the theoretical
aspects.

> Although a clean fix/patch for this would still be a good thing,
> the ringbuffer's are used widely and they function as intended in almost all
> situations.

Sure. I'm not surprized that it works in practice. If the compiler
emits a memory barrier for the volatile memory access, it's all you
need. But technically, it's still undefined behaviour.

> You need not concern yourself with this issue if you are just
> starting out.

Well, for me, that's part of the fun -- figuring out how it's supposed
to be written without invoking U.B.

sg
_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@email-addr-hidden
http://lists.linuxaudio.org/listinfo/linux-audio-dev
Received on Tue Mar 1 20:15:02 2016

This archive was generated by hypermail 2.1.8 : Tue Mar 01 2016 - 20:15:02 EET