You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
use std::sync::{Arc,Mutex};use tokio::sync::Notify;asyncfngood_fn(){let m = Mutex::new(Arc::new(Notify::new()));let v = m.lock().unwrap().clone();
v.notified().await;}asyncfngood_fn_2(){let m = Mutex::new(Arc::new(Notify::new()));let v = m.lock().unwrap();let n = Arc::new(Notify::new());drop(v);
n.notified().await;}asyncfnbad_fn(){let m = Mutex::new(Arc::new(Notify::new()));let inner = m.lock().unwrap();let v = inner.clone();drop(inner);
v.notified().await;}asyncfnbad_fn_2(){let m = Mutex::new(true);let inner = m.lock().unwrap();let e = *inner == true;let n = Arc::new(Notify::new());drop(inner);
n.notified().await;}fntest_fn<F:Send + Sync>(f:F){}fncheck(){test_fn(good_fn());test_fn(good_fn_2());test_fn(bad_fn());test_fn(bad_fn_2());}
I expected to see this happen: This should compile just fine
Instead, this happened: While the good_fn() and good_fn_2() compiles fine, the bad_fn() and bad_fn_2() reports that it's !Send, and thus can't be used.
The error is generally:
Note: future is not Send as this value is used across an await
Worth a note here: if I switch to tokio's mutex implementation, even when using blocking_lock(), this code compiles fine. Something about the rust standard MutexGuard seems to incorrectly be registered as being involved in the await.
It seems to be something about accessing any data on the mutex prior to the await point marks it as non-send, even when the data is explicitly dropped beforehand (and thus has no non-Send data surviving across any await point) so I think it's misreading this.
The Notify used in this example is from tokio with the sync feature enabled, but I'd imagine there are other simpler ways to trigger this too.
❯ RUST_BACKTRACE=1 cargo build
Compiling bug v0.1.0 (/bug)
warning: unused variable: `e`
--> src/lib.rs:29:9
|
29 | let e = *inner == true;
| ^ help: if this is intentional, prefix it with an underscore: `_e`
|
= note: `#[warn(unused_variables)]` on by default
error: future cannot be sent between threads safely
--> src/lib.rs:40:13
|
40 | test_fn(bad_fn());
| ^^^^^^^^ future returned by `bad_fn` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, Arc<Notify>>`
note: future is not `Send` as this value is used across an await
--> src/lib.rs:23:18
|
20 | let inner = m.lock().unwrap();
| ----- has type `std::sync::MutexGuard<'_, Arc<Notify>>` which is not `Send`
...
23 | v.notified().await;
| ^^^^^ await occurs here, with `inner` maybe used later
note: required by a bound in `test_fn`
--> src/lib.rs:35:15
|
35 | fn test_fn<F: Send + Sync>(f: F) {}
| ^^^^ required by this bound in `test_fn`
error: future cannot be sent between threads safely
--> src/lib.rs:41:13
|
41 | test_fn(bad_fn_2());
| ^^^^^^^^^^ future returned by `bad_fn_2` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, bool>`
note: future is not `Send` as this value is used across an await
--> src/lib.rs:32:18
|
28 | let inner = m.lock().unwrap();
| ----- has type `std::sync::MutexGuard<'_, bool>` which is not `Send`
...
32 | n.notified().await;
| ^^^^^ await occurs here, with `inner` maybe used later
note: required by a bound in `test_fn`
--> src/lib.rs:35:15
|
35 | fn test_fn<F: Send + Sync>(f: F) {}
| ^^^^ required by this bound in `test_fn`
warning: unused variable: `f`
--> src/lib.rs:35:28
|
35 | fn test_fn<F: Send + Sync>(f: F) {}
| ^ help: if this is intentional, prefix it with an underscore: `_f`
warning: `bug` (lib) generated 2 warnings
error: could not compile `bug` (lib) due to 2 previous errors; 2 warnings emitted
The text was updated successfully, but these errors were encountered:
TapGhoul
changed the title
Async function is incorrectly declared as being !Send even when nothing !Sync is held over an await border
Async function is incorrectly declared as being !Send even when nothing !Send is held over an await border
May 9, 2025
TapGhoul
changed the title
Async function is incorrectly declared as being !Send even when nothing !Send is held over an await border
Async function is incorrectly declared as being !Send even when nothing !Send is held over an await
May 9, 2025
Worth a note here: if I switch to tokio's mutex implementation, even when using blocking_lock(), this code compiles fine. Something about the rust standard MutexGuard seems to incorrectly be registered as being involved in the await.
The tokio MutexGuard is Send, while the std MutexGuard is !Send. Pthreads (which it internally uses on some platforms) requires unlocking to happen on the same thread as locking, but tokio never uses pthreads for its mutex implementation.
I tried this code:
I expected to see this happen: This should compile just fine
Instead, this happened: While the good_fn() and good_fn_2() compiles fine, the bad_fn() and bad_fn_2() reports that it's !Send, and thus can't be used.
The error is generally:
Worth a note here: if I switch to tokio's mutex implementation, even when using
blocking_lock()
, this code compiles fine. Something about the rust standard MutexGuard seems to incorrectly be registered as being involved in the await.It seems to be something about accessing any data on the mutex prior to the await point marks it as non-send, even when the data is explicitly dropped beforehand (and thus has no non-Send data surviving across any await point) so I think it's misreading this.
The
Notify
used in this example is from tokio with thesync
feature enabled, but I'd imagine there are other simpler ways to trigger this too.Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: