Confidence level: have no idea what I am talking about
Would the following impl make sense?
unsafe impl<T: Sync> Send for Pin<&mut T> {}
Intuitively, it feels like it should be true. We have
impl<T: Send> Send for &mut T
because an &mut
can be used to smuggle values between the threads using mem::replace
, but that's exactly the thing that is prevented by Pin
. Note that we need T: Sync
, because one can get an &T
out of Pin<&mut T>
, so Pin<&mut T>
can be used for sending &T
s.
If this does make sense, can we also change compiler generated futures to have unsafe impl Sync
? I don't think there's any API on the generated futures which is accessible only via &
, so the futures seem to be trivially sync?
If both Pin: Send
and async fn: Sync
are true, does that mean that work-stealing executors can change
pub fn spawn<T>(future: T) -> JoinHandle<T::Output>
where
T: Future + Send + 'static,
T::Output: Send + 'static
to
pub fn spawn<T>(mk_future: F) -> JoinHandle<T::Output>
where
F: FnOnce() + Send,
F::Output: Future + Sync + 'static,
F::Output::Output: Send + 'static
and allow interior interior mutability in async fns?
That is, once an executor gets a Pin<&mut Task>
, they are free to poll the task from whatever thread, even if the Task holds something like &Rc
across an .await
?
(Inspired by all the recent discussion around local executors and TPC, but, most crucially, by https://blaz.is/blog/post/lets-pretend-that-task-equals-thread/)