Continuing the discussion from Manually drop MutexGuard still raise `Future is not Send' error:
I just ran into the same problem, but I think I found a workaround that might help in some cases:
use std::future::Future;
use std::sync::Mutex;
async fn nop() {}
async fn foo() {
let mutex = Mutex::new(());
// I need to comment-in these curly braces for the `Future` to be `Send`
//{
let guard = mutex.lock().unwrap();
drop(guard);
//}
nop().await;
}
fn main() {
let _: Box<dyn Future<Output = ()> + Send> = Box::new(foo());
}
Errors:
Compiling playground v0.0.1 (/playground)
error: future cannot be sent between threads safely
--> src/main.rs:17:50
|
17 | let _: Box<dyn Future<Output = ()> + Send> = Box::new(foo());
| ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:13:10
|
10 | let guard = mutex.lock().unwrap();
| ----- has type `MutexGuard<'_, ()>` which is not `Send`
...
13 | nop().await;
| ^^^^^^ await occurs here, with `guard` maybe used later
14 | }
| - `guard` is later dropped here
= note: required for the cast from `impl Future<Output = ()>` to the object type `dyn Future<Output = ()> + Send`
error: could not compile `playground` due to previous error
When I add the curly braces, the program will compile. The same holds when I use an inner function. (Playground)
Has someone else stumbled upon this problem too? What your usual solution to it?
Thanks to @Yandros for pointing me to the corresponding issues on GitHub:
I guess the best way would be to add curly braces or some inner function to give a hint to the compiler, and maybe add a TODO to remove them when these issues are closed.
In my real-world code, it looks like this:
- let synced = self.shared.synced.lock();
- if synced.unseen == 0 && synced.rcvr_count > 0 {
- break synced;
- }
- let notified = self.shared.notify_sndr.notified();
- drop(synced);
- notified.await;
+ {
+ let synced = self.shared.synced.lock();
+ if synced.unseen == 0 && synced.rcvr_count > 0 {
+ break synced;
+ }
+ self.shared.notify_sndr.notified()
+ }.await;
The red code fails to compile, the green code compiles.
Oh, I just noticed one of the comments on GitHub mentions the workaround to add braces as well.