-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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 unit test showing some unexpected behaviour of mpsc::channel #2020
Add unit test showing some unexpected behaviour of mpsc::channel #2020
Conversation
Here is a loom test that catches the problem: #[test]
fn try_recv() {
loom::model(|| {
use crate::sync::{mpsc, Semaphore};
use loom::sync::{Arc, Mutex};
const PERMITS: usize = 2;
const TASKS: usize = 2;
const CYCLES: usize = 1;
struct Context {
sem: Arc<Semaphore>,
tx: mpsc::Sender<()>,
rx: Mutex<mpsc::Receiver<()>>,
}
fn run(ctx: &Context) {
block_on(async {
let permit = ctx.sem.acquire().await;
println!(" + before try_recv");
assert_ok!(ctx.rx.lock().unwrap().try_recv());
crate::task::yield_now().await;
assert_ok!(ctx.tx.clone().try_send(()));
println!(" + after try_send");
drop(permit);
});
}
let (tx, rx) = mpsc::channel(PERMITS);
let sem = Arc::new(Semaphore::new(PERMITS));
let ctx = Arc::new(Context { sem, tx, rx: Mutex::new(rx) });
for _ in 0..PERMITS {
assert_ok!(ctx.tx.clone().try_send(()));
}
let mut ths = Vec::new();
for _ in 0..TASKS {
let ctx = ctx.clone();
ths.push(thread::spawn(move || {
run(&ctx);
}));
}
run(&ctx);
for th in ths {
th.join().unwrap()
}
});
} |
What is the status of this PR? |
The operations on semaphore are not linearizable. For example, if in the call to |
As far as I understand it it's not the semaphore causing the problems. e.g. when replacing the tokio channel by crossbeam the problem no longer exists. I think the problem exists because |
EDIT: I completely missed the fact that this is single consumer queue, so non-linearizability of add_permits is non-issue. Sorry for the noise. |
Does this mean the issue should be closed? |
@Darksonn The example demonstrates that I would generally say that guarantees provided by the queue merit mention in Note that I didn't open this PR. |
That issue still exists: One worker calls |
@bikeshedder https://github.com/stjepang/async-channel might be a more approriate replacement because crossbeam's channels aren't compatible with the async-ecosystem. |
@cynecx crossbeam works great and is very compatible with the async-ecosystem since it provides lockfree channel implementations. You just can't This issue is about tokio and the current channel implementation is currently broken when using |
@bikeshedder Oh sorry, I thought we were talking about crossbeam's channels :). That sounds reasonable. |
We probably should remove these APIs in 1.0 until we can fix them. |
Sounds like we should just add this as a note to the docs? What do others think? |
I mean, how hard is this to fix? |
@Darksonn medium hard. More than quick patch. |
The mpsc `try_recv()` functions have an issue where a sent message happens-before a call to `try_recv()` but `try_recv()` returns `None`. Fixing this is non-trivial, so the function is removed for 1.0. When the bug is fixed, the function can be added back. Closes #2020
The mpsc `try_recv()` functions have an issue where a sent message happens-before a call to `try_recv()` but `try_recv()` returns `None`. Fixing this is non-trivial, so the function is removed for 1.0. When the bug is fixed, the function can be added back. Closes #2020
Is there any issue for adding |
@sunjay For now you can do I have opened #3350 to track adding it back. |
This commit runs `cargo upgrade` which introduces 3 breaking changes: First, the `gen_range` function from the `rand` crate now takes a range as a single argument rather than as two params. Good change! Next, tokio is now at 1.0! We make changes to 1/ the runtime builder (for the blocking driver), 2/ where we don't need mutable refs anymore, 3/ move away from try_recv as described in tokio-rs/tokio#2020 and 4/ replace `delay_for` with `sleep`. The main reason for this upgrade, beyond hygiene, is to pick up a new version of rusoto which we will use shortly.
This commit runs `cargo upgrade` which introduces 3 breaking changes: First, the `gen_range` function from the `rand` crate now takes a range as a single argument rather than as two params. Good change! Next, tokio is now at 1.0! We make changes to 1/ the runtime builder (for the blocking driver), 2/ where we don't need mutable refs anymore, 3/ move away from try_recv as described in tokio-rs/tokio#2020 and 4/ replace `delay_for` with `sleep`. The main reason for this upgrade, beyond hygiene, is to pick up a new version of rusoto which we will use shortly.
This commit runs `cargo upgrade` which introduces 3 breaking changes: First, the `gen_range` function from the `rand` crate now takes a range as a single argument rather than as two params. Good change! Next, tokio is now at 1.0! We make changes to 1/ the runtime builder (for the blocking driver), 2/ where we don't need mutable refs anymore, 3/ move away from try_recv as described in tokio-rs/tokio#2020 and 4/ replace `delay_for` with `sleep`. The main reason for this upgrade, beyond hygiene, is to pick up a new version of rusoto which we will use shortly.
This is the fixed version of PR #1997