The idiomatic way to implement a Future

I am trying to implement a Future , my idea is

  1. the Future will hold a done : Arc<AtomicBool>
  2. on first poll of the Future , it will start a thread to emulate a background work , done will be shared by the thread
  3. when work is done , the thread will set done to true

the code is as follow , is this the idiomatic way?
Currently , I wake up the async runtime unconditionally (line A) , I want it smarter , that is , let the thread wake up async runtime when work is done (line B) , but this line can't compile for now. So is it correct to pass Context to a thread?

struct MyFuture{
  started : bool,
  done : Arc<AtomicBool>,
  id   : u8,
}

impl Future for MyFuture {
  type Output = bool;
  fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
    println!("poll {}",self.id);
    if self.done.load(Ordering::Relaxed) {
      Poll::Ready(true)
    } else {
      if !self.started {
        let done = self.done.clone();
        let id = self.id;
        thread::spawn(move || {    
          thread::sleep_ms(5);
          println!("work {:02} done",id);
          done.store(true,Ordering::Relaxed);
          // cx.waker().wake_by_ref();   // B
        });
        self.started = true;
      }
      cx.waker().wake_by_ref();          // A
      Poll::Pending
    }
  }
}

fn simulate(id:u8)->MyFuture {
  let done = Arc::new(AtomicBool::new(false));
  MyFuture{started:false,done,id}
}

#[tokio::main(flavor="current_thread")]
async fn main() {
  let f = (0..10).map(|x| {
    tokio::spawn(simulate(x))
  });
  for f in f {
    f.await;
  }
}

What are you actually trying to do? This sounds like an XY problem at first glance.

XY problem? I've never heard of that :grinning:. I cut my question to how to pass the Context to a thread.

Basically it seems like what you're asking for isn't what you actually need. Hence why I ask what you're actually trying to do here.

the compiler error is

`cx` is a reference that is only valid in the associated function body

maybe my whole design is wrong.

Similarly to done.clone(), you also need to store cx.waker.clone() .

great! I should read the doc carefully.

Note that the impl Future itself is not a beginner topic since it's not an easy task. Usually you get the leaf futures from the libraries including the async runtime and combine them with futures crate, and/or .await it.

If you're on tokio, you can use its OnceCell with task::spawn_blocking() operation.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.