On Tue, Mar 1, 2016 at 6:40 PM, Paul Davis <p...@linuxaudiosystems.com> wrote: > On Tue, Mar 1, 2016 at 12:09 PM, Sebastian Gesemann <s.gesem...@gmail.com> > wrote: >> >> 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. > > the evil that lock-free data structures seek to avoid is mutual exclusion > that involves stopping thread execution. they do not require that things are > atomic in either the weak or strong sense, but they do require that the data > structures remain consistent and accurate from the POV of the threads that > use them.
Exactly. Specifically, I would want to make sure that the consumer thread sees the update to the write pointer *not before* the updates to the buffer's memory. This was my concern because memory access with three levels of partly shared caches between cores is more complicated than possible instruction reorderings. But by now I have convinced myself that this is guaranteed if the producer writes a new value to write_pos with *release semantics* after updating the buffer and the consumer loads the value of write_pos with *acquire semantics*. http://en.cppreference.com/w/cpp/atomic/memory_order > [...] > the implementation inside Ardour uses glib's atomic wrappers to make the > second assumption strong. > https://github.com/Ardour/ardour/blob/master/libs/pbd/pbd/ringbuffer.h Nice. Yeah, it seems glib's atomics make the strongest possible memory ordering guarantee (more than you actually need in this ringbuffer case). @all: Thank you for your responses. I'm going to use my own ringbuffer using C++11's std::atomics. @Paul: As for the rest of the code, I just noticed a couple of other things you might be interested in: lines 103-107 are if (w > r) { return w - r; } else { return (w - r + size) & size_mask; } If I'm not miskaten, this could be simplified to return (unsigned)(w - r) & size_mask; The "(unsigned)" isn't even necessary because of integral promotion, but I'd prefer this to be explicit. The class violates the "rule of three". It allows a user to copy-construct as well as copy-assign such ringbuffer objects resulting in double-free errors. I'd prefer to manually disable the copy constructor and assignment operator. Right now these special member functions can be generated by the compiler and would do the wrong thing. I'd mark the constructor as explicit to avoid accidental int-to-buffer conversions (like std::vector). Cheers! sg _______________________________________________ Linux-audio-dev mailing list Linux-audio-dev@lists.linuxaudio.org http://lists.linuxaudio.org/listinfo/linux-audio-dev