New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add fn force_push to ArrayQueue #789
Conversation
Two test cases failed on CI, |
Ok, so it turns out both test cases that failed had bugs in them, which are now hopefully fixed. |
Something just occurred to me, instead of a new queue type, this could simply be a second flavor of push on ArrayQueue, perhaps |
Anything missing, that I could work on? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! The implementation looks good to me.
force_push makes it possible for ArrayQueue to be used as a ring-buffer.
.is_ok() | ||
{ | ||
// Move the tail. | ||
self.tail.store(new_tail, Ordering::SeqCst); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be CAS, as the tail may have changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's actually not necessary. Up until the point where a thread attempts to update the head, it has only read state that depends on tail, then moves the head only if it lags by exactly one lap. Immediately after the head is updated, tail has not changed, so all other threads that are concurrently attempting to push will invariably fail the CAS on head, because it no longer lags the tail by exactly one lap. This means that until the thread that moved the head updates the tail, no other thread attempting to push can make progress and update the tail. As for threads attempting to pop, they never move the tail either, so we don't need to worry about the tail updating underneath us here.
Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bors r+
Build succeeded: |
800: Prepare for the next release r=taiki-e a=taiki-e - crossbeam-channel 0.5.2 -> 0.5.3 - Fix panic on very large timeout. (#798) - crossbeam-epoch 0.9.7 -> 0.9.8 - Make `Atomic::null()` const function at 1.61+. (#797) - crossbeam-queue 0.3.4 -> 0.3.5 - Add `ArrayQueue::force_push`. (#789) - crossbeam-utils 0.8.7 -> 0.8.8 - Fix a bug when unstable `loom` support is enabled. (#787) Co-authored-by: Taiki Endo <te316e89@gmail.com>
Published in crossbeam-queue 0.3.5. |
this is possible now that crossbeam-rs/crossbeam#789 has been released with v0.3.5.
this is possible now that crossbeam-rs/crossbeam#789 has been released with v0.3.5.
this is possible now that crossbeam-rs/crossbeam#789 has been released with v0.3.5.
This is an attempt to implement a straightforward MPMC ring-buffer and close #680.
This proposal adds a new method
push_or_swap
toArrayQueue
, that atomically swaps the oldest element when the queue is full, instead of returningErr
back to the caller likepush
does. As such,push_or_swap
never fails to insert the element into the queue.I couldn't find any benchmarks I could run, (am I missing anything obvious?), however I did run benchmarks from ring-channel where I compared this implementation against an emulation of a ring-buffer, that keeps popping elements until pushing succeeds, i.e. something like the following:
I got the results below on my machine, which show that
push_or_swap
fares much better when capacity is low and the probability that pushing fails is high (the baseline was set to thepush
-based implementation).total_number_of_messages_received / total_number_of_messages_sent
.SB/PxR/C
, where S is the size of the element in bytes, P is the number of threads producing, R the number of threads consuming, and C is the capacity of the ring-buffer: