Context:
I need to use Mutex
es (or even better: RefCell
s if that was possible) in some async closures, blocks, or functions. I would like the resulting Future
s to be Send
. The locking (or borrowing, respectively) will only be necessary for a short time while no async operations are executed.
Problem:
If I use a block expression to limit the scope of the MutexGuard
(or mutable borrow, respectively), I can make the Future
(named "_sendable_future
") be Send
. But it won't work with the "_nonsend_future
" below. The only difference is that in the latter case, I use a manual drop
instead of making an extra block expression and letting the guard
(or borrow
, respectively) drop because their drop scope ends.
Question:
Why do these two cases behave differently? Is that because the compiler doesn't "notice" that the values are dropped when constructing the Future
from the async
block?
Thanks for your help, I include a playground example below:
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::sync::Mutex;
async fn some_func() {}
fn main() {
// This works fine:
let cell1 = RefCell::new(0);
let mutex1 = Mutex::new(0);
let _sendable_future: Pin<Box<dyn Future<Output = ()> + Send>> =
Box::pin(async move {
{
let mut borrow = cell1.borrow_mut();
let mut guard = mutex1.lock().unwrap();
*borrow += 1;
*guard += 1;
}
some_func().await;
});
// But this doesn't work:
let cell2 = RefCell::new(0);
let mutex2 = Mutex::new(0);
// (unless we remove the `Send` bound)
let _nonsend_future: Pin<Box<dyn Future<Output = ()> + Send>> =
//let _nonsend_future: Pin<Box<dyn Future<Output = ()>>> =
Box::pin(async move {
let mut borrow = cell2.borrow_mut();
let mut guard = mutex2.lock().unwrap();
*borrow += 1;
*guard += 1;
drop(borrow);
drop(guard);
some_func().await;
});
}
(Edit: Formatting only)