Skip to content
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

Fallback to Parking in std::sync::mpsc Channels #125204

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ibraheemdev
Copy link
Member

@ibraheemdev ibraheemdev commented May 17, 2024

Currently, the queues used by the mpsc channel flavors are not lock-free. The linearization point of a send or receive is moving the tail or head index respectively, meaning that senders and receivers must spin if they see an updated head/tail despite the corresponding value not being written yet. Blocking in such a case is not possible as sends might notify a receiver even though they are not yet visible due to a lagging sender holding up the channel, or vice versa, leading to missed wakeups.

The current solution of unbounded spinning can lead to issues, especially on platforms with a single core or custom thread priorities. One way to allow falling back to blocking is if waiters that see more values in the channel after being woken up notify any other waiters, making up for any missed notifications. However, this ends up being quite expensive and can lead to many unnecessary wakeups. The solution implemented by this PR is wakeup throttling, as used by tokio and other userspace schedulers. The new algorithm is in sync/mpmc/waker.rs.

Should resolve #114851 and #112723. An alternative solution is to introduce a non-linearizable version of try_recv, but fixing the unbounded spinning is important regardless. This PR leaves a couple cases of unbounded spinning when discarding the messages in the unbounded channel that can be addressed in a later PR, those should not be a large concern.

There are a couple other cosmetic changes included in this PR that were not previously ported from crossbeam. Hopefully they shouldn't distract from the primary changes. Downstream patch: crossbeam-rs/crossbeam#1105.

r? @Amanieu

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 17, 2024
@rust-log-analyzer

This comment has been minimized.

@ibraheemdev ibraheemdev force-pushed the chan-no-spin branch 2 times, most recently from 63a6e25 to 23fb55f Compare May 17, 2024 22:14
@ibraheemdev ibraheemdev marked this pull request as draft May 17, 2024 23:10
@ibraheemdev ibraheemdev marked this pull request as ready for review May 18, 2024 01:13
Comment on lines +279 to +286
// Because writes to the channel are also sequentially consistent,
// this creates a total order between storing a value and registering a waiter.
let state = self.state.load(Ordering::SeqCst);

// If a notification is already set, the waker thread will take care
// of further notifications. Otherwise we have to notify if there are waiters.
if (state >> WAKER) > 0 && (state & NOTIFIED == 0) {
return self
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given the fetch_update() is likely to be a a compare_exchange_weak loop already, could it go straight into it instead of doing this extra load check before it?

/// on the channel, as well as creates a chain that makes up for lost wakeups,
/// allowing threads to park even if the channel is in an inconsistent state.
struct WakerState {
state: AtomicU64,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on making this an AtomicUsize for 32bit platforms?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Channel sending/receiving ends up spinlooping and deadlocking
6 participants