Pin 与 Unpin

  • std::pin::Pin
  • std::maker::Unpin
  • std::maker::PhontomPinned
  • impl !Unpin for T

Pin [source]

Rust展开
123456789101112131415161718192021
/// A pinned pointer.
///
/// This is a wrapper around a kind of pointer which makes that pointer "pin" its
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
/// *See the [`pin` module] documentation for an explanation of pinning.*
///
/// [`pin` module]: self
//
// Note: the `Clone` derive below causes unsoundness as it's possible to implement
// `Clone` for mutable references.
// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311> for more details.
#[stable(feature = "pin", since = "1.33.0")]
#[lang = "pin"]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct Pin<P> {
    // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to://   - deter downstream users from accessing it (which would be unsound!),//   - let the `pin!` macro access it (such a macro requires using struct//     literal syntax in order to benefit from lifetime extension).// Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives.#[unstable(feature = "unsafe_pin_internals", issue = "none")]#[doc(hidden)]pub pointer: P,
}

Pin 可以确保被任何类型的指针T指向的数据有一个固定的位置,不能被移动和释放。

需要Pin的核心诉求是,async/await 需要一个自引用的结构体(self-referential-structs), 它表示一个结构体当中的一个字段指向了当前结构的另一个字段。

Rust展开
1234
struct SelfRefer {
    val: String,
    pointer_to_val: *mut String
}

这个结构体中,如果val指向的String被移动,则pointer_to_val将变成非法地址, 会引发内存安全问题。而Pin的出现就是为了避免这种场景的出现,从而保证内存安全。

对于Future

Rust展开
1234567
let f1 = /** ... */  //Future1
let f2 = /** ... */  //Future2

async move{ 
    f1.await;
    f2.await;
}

在rust底层会将上述代码编译成一个匿名结构体

Rust展开
123456789101112131415161718192021222324252627282930
struct AsyncFuture {
    f1: Future1,
    f2: Future2,
    state: State
}

enum State {
    AwaitF1.
    AwaitF2,
    Done
}

impl Future  for AsyncFuture {
    type Output = ()
    fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>)-> Poll<()> {
        loop {
            match self.state {
                State::AwaitF1 => match self.state.f1.poll() {
                    Poll::Ready(()) => self.state = State::AwaitF2,
                    Poll::Penging => return Poll::Penging
                },
                State::AwaitF2 => match self.state.f2.poll() {
                    Poll::Ready(()) => self.state = State::Done,
                    Poll::Penging => return Poll::Penging
                },
                State::Done => return Poll::Ready(())
            }
        }
    }
}

- roadup -