Linux のコマンドライン学習完全集 [Synchronizer がビジネスユーザー向けの基本的な情報理論をアップデートします]

Rust のランタイムとは何ですか? 完全に理解するために、サードパーティのクレートを使用せずにおもちゃのランタイムを実装しました。複雑なスケジューリング アルゴリズムがない (グローバル タスク キューのみ) ため、おもちゃと呼ばれています。

サードパーティ クレート クロスビームを使用する mpmc (マルチプロデューサー、マルチコンシューマー) を除き 、コードの残りの部分は手書きです。

こんな感じで遊べるよ

fn main() {
    let toy = Toy::new();

    for i in 1..=20 {
        toy.spawn(async move {
            let ret = FakeIO::new(Duration::from_secs(i)).await;
            println!("{:?}: {:?}", thread::current().id(), ret);
        })
    }

    toy.run(4); // 4 threads
}

その中でもFakeIOも十分シンプルです

pub struct FakeIO {
    finished: Arc<AtomicBool>,
    duration: Duration,
}

impl Future for FakeIO {
    type Output = Duration;

    fn poll(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        if self.finished.load(Ordering::Acquire) {
            return Poll::Ready(self.duration);
        }

        let finished = self.finished.clone();
        let waker = cx.waker().clone();
        let duration = self.duration;

        thread::spawn(move || {
            thread::sleep(duration);

            finished.store(true, Ordering::Release);

            waker.wake();
        });

        Poll::Pending
    }
}

データ構造

データ構造は以下の通りです(  Tokio の設計を参考にしています)

struct Task {
    raw: RawTask,
}

unsafe impl Send for Task {}
unsafe impl Sync for Task {}

struct RawTask {
    ptr: NonNull<Header>, // pointer to Cell<T> where T: Future
}

struct Header {
    // todo: maybe replace the Mutex<State> with AtomicUsize
    state: Mutex<State>,
    vtable: &'static Vtable,
    sender: crossbeam::channel::Sender<Task>,
}

#[derive(Default)]
struct State {
    running: bool,
    notified: bool,
    completed: bool,
}

/// #[repr(C)] make sure `*mut Cell<T>` can cast to valid `*mut Header`, and backwards. 
/// In the default situation, the data layout may not be the same as the order in which the fields are specified in the declaration of the type
/// 默认情况下 Rust 的数据布局不一定会按照 field 的声明顺序排列
/// [The Default Representation](https://doc.rust-lang.org/reference/type-layout.html?#the-default-representation)
///
/// [playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=39ac84782d121970598b91201b168f82)
/// 
/// you can easilly view the data layout with this crate https://github.com/hangj/layout-rs
#[repr(C)]
struct Cell<T: Future> {
    header: Header,
    future: T,
    output: Option<T::Output>,
}

struct Vtable {
    poll_task: unsafe fn(NonNull<Header>),
    clone_task: unsafe fn(NonNull<Header>) -> NonNull<Header>,
    drop_task: unsafe fn(NonNull<Header>),
}

その中で注目すべきものは次のとおりです。

  • RawTask 内側のものは ptr 実際に指しています NonNull<Cell<T: Future>>
  • Cell<T: Future> フラグが付けられており #repr(C)、理由はコメントに記載されています
  • vtableこの設計では、 Waker の vtable を参照します 。これは、型情報を保存する汎用関数の使用と同等であり、後で生のポインターを元の型に復元するのが容易になります。

楽しむ!

おすすめ

転載: blog.csdn.net/udisi658996666/article/details/132698210