polyfractal/bounded-spsc-queue

Option to push + drop old data

Closed this issue · 3 comments

I'm working on some audio programming applications where I'd actually like to drop the old data in the queue (and still push), rather than drop the new stuff (and never push it). Would it be possible to implement a version of this method on the Producer?

This is a very common application in audio programming -- we always want to update the buffer with the newest data, even if no one's listening -- so it would be great to have available in a library like this one.

FYI, I've posted this on Reddit, but also put the question out to one of the creators behind PortAudio via email. It could potentially be a bad idea, in which case I'm happy to close the comment.

Answered a bit on Reddit, but I think the answer is basically there's no particular reason the queue was setup like this, other than personal preference at the time. I haven't thought too deeply about it (my rust laptop just died, so haven't had a chance to fiddle around with it), but I don't see why it wouldn't work.

It'd take some adjusting of who bumps which pointer, and obviously the push/pop semantics change. I think the best way to implement it is probably to specialize each of the queue types and then just create a different one via param on the builder function. That way it doesn't need a bunch of conditionals everywhere, semantics are clear, etc.

But again, I haven't thought too heavily on this, so there may be a better way to do it. I don't see any reason why i t couldn't be done though!

Via Phil Burk, of portaudio & portmidi -- he said that basically two threads should never modify the one index, even if it's atomic. The reasoning is that although increment can be atomic with atomic usizes, read-buffer-and-increment cannot, so you don't know whether you're getting corrupted data.

Even if the reader only has immutable access to the read index, you still have a potential problem:

  1. Reader queries read index
  2. Writer queries "space available"; not enough space available in buffer
  3. Writer overwrites memory at current read index
  4. Writer increments read index
  5. Reader reads the new memory from writer using read index stored from step 1

It sounds implausible, but in a practical (audio) situation chances are that your writer is in the audio callback thread and is running at top priority, above just about everything else on the system. Your reader then gets pushed to the back, assuming they're competing for the same core anyway, and sleeps for a moment while the writer finishes its work.

Anyway, I'm closing this, but thanks for taking a look.