bus
bus copied to clipboard
Non-blocking destructive bus
Hi!
I have a need for a non-blocking sender. When the bus is full, I'd like to overwrite oldest non-read elements (so readers might skip items if they're too slow) rather than blocking. Bus::try_broadcast
is not working for me since I still need to send the new message when the bus is full.
Is it something this library might add?
Hmm, that's an interesting feature... It'd be pretty tricky to add, because the value may already have gone out to some readers, and others may be accessing it concurrently. I think doing this in a race-free way would be pretty tough. If you have an idea for how to do it though, I'd be happy to take a look at a PR!
I'm still reading through the code, so I have an incomplete view, but I think it would go like that:
- We need an atomic counter (called
num_readers
) and an atomic bool (calledwriter_waiting
). - When a reader wants to receive a value:
- It spins-lock until
writer_waiting
is false - It increases
num_readers
- If the head pointer is higher than the reader pointer, update the reader pointer to the head pointer.
- It copies the value out of the bus
- It decreases
num_readers
- It spins-lock until
- When a writer wants to send a value and the bus is full:
- It spin-locks until
writer_waiting.compare_and_swap(false, true)
returns false - It spin-lock until
num_readers
is 0 (should be the duration of a few memcopys) - It overwrites the oldest value
- It updates the head/tail pointers
- It sets
writer_waiting
to false
- It spin-locks until
The counter and bool might be replaced by a RWLock
.
This ensures that no-one is reading the cell we are overwriting, and limits the time the writer waits (to the time taken by mem-copying the value out of the bus by the outstanding readers).
I'm not 100% sure it should share the code of the current implementation: it risk adding complexity/overhead to cases where it's not needed, while not benefiting from features of the current implementation. :S
Hmm, yeah, I'd worry that this would end up adding significant contention for both reads and writes, which is something the current implementation tries very hard to avoid. It could be that it should be its own implementation that we can optimize separately?