Task execution pause/resume in Rust async? (tokio) - rust

How can I pause an async task in Rust?
Swift has withCheckedContinuation(function:_:)
that pauses current task and returns saved context that can be resumed at desired time. (a.k.a. call/cc)
tokio has tokio::task::yield_now, but it can resume automatically, so that's not what I'm looking for. I mean "pause" that will never resume without explicit command.
Now I'm looking into tokio manual. It defines several synchronization features in tokio::sync module, but I couldn't find a function to pause a task directly. Am I supposed to use only the synchronization feature to simulate the suspend? Or am I missing something here?

tokio::sync::oneshot can be used for this purpose. It gives you two objects: one a future, and the other a handle you can use to cause the future to resolve. It also conveys a value, but that value can be just () if we don't need it.
In the following runnable example, main() is the task being paused and the task which resumes it is spawned, because that's the simplest thing to do; but in a real application you'd presumably pass on the sender to something else that already exists.
use std::time::Duration;
use tokio::spawn;
use tokio::time::sleep;
use tokio::sync::oneshot;
#[tokio::main]
async fn main() {
println!("one");
let (sender, receiver) = oneshot::channel::<()>();
spawn(async move {
sleep(Duration::from_millis(400));
println!("two");
if let Err(_) = sender.send(()) {
println!("oops, the receiver dropped");
}
});
println!("...wait...");
match receiver.await {
Ok(()) => println!("three"),
Err(_) => println!("oops, the sender dropped"),
}
}
Note that this is not a special feature of the oneshot channel: any future which you can control the resolution of can be used for this purpose. oneshot is appropriate when you want to hand out a specific handle to this one paused task. If you instead wanted many tasks to wake up on a single notification, you could use tokio::sync::watch instead.

I don't know anything built-in, but you can build your own.
You need access to the Waker to unpark a future. You also need to keep track of whether the futute has been manually unparked, because futures can be waked by the runtime even if nobody ordered them to.
There are various ways to write this code, here is one:
// You can get rid of this `Unpin` bound, if you really want
pub async fn park(callback: impl FnOnce(Parker) + Unpin) {
enum Park<F> {
FirstTime { callback: F },
SecondTime { unparked: Arc<AtomicBool> },
}
impl<F: FnOnce(Parker) + Unpin> Future for Park<F> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Self::SecondTime { unparked } = &*self {
return if unparked.load(Ordering::SeqCst) {
Poll::Ready(())
} else {
Poll::Pending
};
}
let unparked = Arc::new(AtomicBool::new(false));
let callback = match std::mem::replace(
&mut *self,
Self::SecondTime {
unparked: Arc::clone(&unparked),
},
) {
Self::FirstTime { callback } => callback,
Self::SecondTime { .. } => unreachable!(),
};
callback(Parker {
waker: cx.waker().clone(),
unparked,
});
Poll::Pending
}
}
Park::FirstTime { callback }.await
}
Then you call it like park(|p| { ... }).await.
Example.

Related

Async: how to keep using the same future in a loop with select (no_std environment)?

I have two async functions: get_message and get_event. I'd like to perform an action whenever a message arrives or an event comes and do that forever in an infinite loop.
The simplified setup looks like this:
use futures::{future::select, future::Either, pin_mut};
impl MsgReceiver {
async fn get_message(&mut self) -> Message { /* ... */ }
}
impl EventListener {
async fn get_event(&mut self) -> Event { /* ... */ }
}
async fn eternal_task(receiver: MsgReceiver, listener: EventListener) -> ! {
let get_msg_fut = receiver.get_message();
pin_mut!(get_msg_fut);
loop {
let get_event_fut = listener.get_event();
pin_mut!(get_event_fut);
match select(get_event_fut, get_msg_fut).await {
Either::Left((ev, r_get_msg_fut)) => {
/* react to the event */
// r_get_msg_fut is not done, how to reuse it in the next iteration?
}
Either::Right((msg, r_get_event_fut)) => {
/* react to the message */
// it's fine to drop get_event_fut here
// the following line causes a double-mut-borrow error on receiver,
// despite receiver isn't borrowed anymore (the old future is completed and dropped)
let new_future = receiver.get_message();
}
};
}
}
I have three major questions here:
When an event comes first, how to tell rust that I want to reuse the incomplete get_message future on the next loop iteration?
When a message comes first, how to construct a new future without a borrow error?
When (2) is solved, how to put the new future into the same pinned memory location and use it on the next loop iteration?
I had success using this, but could not get rid of the Box::pin
use futures::{future::select, future::Either, pin_mut};
use std::sync::Mutex;
#[derive(Debug)]
struct MsgReceiver;
#[derive(Debug)]
struct EventListener;
#[derive(Debug)]
struct Message;
#[derive(Debug)]
struct Event;
impl MsgReceiver {
async fn get_message(&mut self) -> Message {
Message
}
}
impl EventListener {
async fn get_event(&mut self) -> Event {
Event
}
}
async fn eternal_task(receiver: MsgReceiver, mut listener: EventListener) -> ! {
let receiver = Mutex::new(receiver);
let mut f = None;
loop {
let get_msg_fut = match f.take() {
None => {
let mut l = receiver.lock();
Box::pin(async move {
l.get_message().await
})
}
Some(f) => f,
};
let get_event_fut = listener.get_event();
pin_mut!(get_event_fut);
match select(get_event_fut, get_msg_fut).await {
Either::Left((ev, r_get_msg_fut)) => {
/* react to the event */
// store the future for next iteration
f = Some(r_get_msg_fut);
}
Either::Right((msg, r_get_event_fut)) => {
/* react to the message */
}
};
}
}
#[tokio::main]
async fn main() {
eternal_task(MsgReceiver, EventListener).await;
}
I think this is tricky to get right, even with unsafe which would probably be needed to accomplish this. Persisting and reusing the same variables isn't too hard, its actually #2 that's the hardest (at least with the current borrow checker).
I found a solution that totally circumvents the problem by using the async-stream crate to provide an intermediary:
async fn eternal_task(mut receiver: MsgReceiver, mut listener: EventListener) -> ! {
let combined = futures::stream::select(
stream! { loop { yield Either::Left(receiver.get_message().await); } },
stream! { loop { yield Either::Right(listener.get_event().await); } },
);
pin_mut!(combined);
while let Some(msg_or_evt) = combined.next().await {
match msg_or_evt {
Either::Left(msg) => {
// do something with msg
}
Either::Right(evt) => {
// do something with evt
}
};
}
unreachable!()
}
It uses the stream! macro to generate a type that continuously calls and yields values from .get_message() and .get_event(). It then uses futures::stream::select and Either to combine them. And then its just a matter of looping over the results. It works in #![no_std].

Why do asynchronous tasks (functions) not run unless awaited?

In Rust I have found that an asynchronous task or function (let's even say a future) is not invoked in the runtime unless it is awaited. In other languages such as C# or NodeJS it is possible to define async tasks and run them concurrently as an async task is meant to provide non-blocking IO. For instance:
public Task Run();
public Task ListenToMusic();
public async Task RunAndListenToMusic() {
Task run = Run(); // the task is already running
Task listenToMusic = ListenToMusic(); // the task is already running
await Task.WhenAll(run, listenToMusic);
}
I have tested this mechanism in Rust using a for loop that actually prints out sequential numbers and found that, they are always executed in order, meaning that the second task is run after the first one.
For people like me who are from the world of dotnet or Java, this is a weird behavior. What is actually going on, I searched but I need someone to explain this in a little bit more details and more simply.
Here's some Rust code that is equivalent to your example:
use tokio; // 1.14.0
async fn task1() {
for i in 0..10 {
println!("Task 1: {}", i);
}
}
async fn task2() {
for i in 0..10 {
println!("Task 2: {}", i);
}
}
#[tokio::main]
async fn main() {
let t1 = task1();
let t2 = task2();
tokio::join!(t1, t2);
}
Playground
If you run this code, you will notice that it executes all of task1 before executing task2. This is expected because execution is single-threaded, so task1 will run so long as it doesn't attempt a blocking operation. However if we add blocking operations (here I've used sleep, but the same goes for I/O operations):
use std::time::Duration;
use tokio; // 1.14.0
async fn task1() {
for i in 0..10 {
println!("Task 1: {}", i);
tokio::time::sleep (Duration::from_millis (1)).await;
}
}
async fn task2() {
for i in 0..10 {
println!("Task 2: {}", i);
tokio::time::sleep (Duration::from_millis (1)).await;
}
}
#[tokio::main]
async fn main() {
let t1 = task1();
let t2 = task2();
tokio::join!(t1, t2);
}
Playground
Now we see that operations are interleaved: when a task blocks the other tasks get a chance to run, which is the whole point of async programming.

Filesystem watch in Rust

I'm trying to implement a filesystem watcher in Rust. I can receive events when filesystem objects have changed but determining what change was made has me stumped. I found code on the latest released version of the Notify package here that takes me almost the whole way there.
How can I extract the path and type out of the event? The event is an enumerated type, yet somehow when it's printed, I see all the info I want.
I am obviously missing something very fundamental.
use notify::{watcher, RecursiveMode, Watcher};
use std::sync::mpsc::channel;
use std::time::Duration;
fn main() {
let (tx, rx) = channel();
let mut watcher = watcher(tx, Duration::from_secs(10)).unwrap();
watcher
.watch("/tmp/path", RecursiveMode::Recursive)
.unwrap();
loop {
match rx.recv() {
Ok(event) => {
// **>> event.filename? event.type? how?
println!("{:?}", event);
}
Err(e) => println!("watch error: {:?}", e),
}
}
}
Using a debounced watcher, the event you get is of type DebouncedEvent. The enum variant specifies the type, and its contents is the path(s). To get it out of the event, you should match on the event for the desired event types:
match &event {
Read(path) => {
// do thing
}
Rename(src, dest) => {
// do other thing
}
_ => () // don't care about other types
}

Why does this Delay future inside poll() not work in my custom Stream type?

I want to print "Hello" once a second.
Quoting the doc:
Futures use a poll based model. The consumer of a future repeatedly calls the poll function. The future then attempts to complete. If the future is able to complete, it returns Async::Ready(value). If the future is unable to complete due to being blocked on an internal resource (such as a TCP socket), it returns Async::NotReady.
My poll function returns NotReady if Delays return is NotReady, but nothing is printed to stdout.
use futures::{Async, Future, Stream}; // 0.1.25
use std::time::{Duration, Instant};
use tokio::timer::Delay; // 0.1.15
struct SomeStream;
impl Stream for SomeStream {
type Item = String;
type Error = ();
fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
let when = Instant::now() + Duration::from_millis(1000);
let mut task = Delay::new(when).map_err(|e| eprintln!("{:?}", e));
match task.poll() {
Ok(Async::Ready(value)) => {}
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(err) => return Err(()),
}
Ok(Async::Ready(Some("Hello".to_string())))
}
}
fn main() {
let s = SomeStream;
let future = s
.for_each(|item| {
println!("{:?}", item);
Ok(())
})
.map_err(|e| {});
tokio::run(future);
}
The main issue here is that state management is missing. You are creating a new Delay future every time the stream is polled, rather than holding on to it until it's resolved.
This would lead to never seeing any items coming out of the stream, since these futures are only being polled once, likely yielding NotReady each time.
You need to keep track of the delay future in your type SomeStream. In this case, one can use an option, so as to also identify whether we need to create a new delay.
#[derive(Debug, Default)]
struct SomeStream {
delay: Option<Delay>,
}
The subsequent code for SomeStream::poll, with better error handling and more idiomatic constructs, would become something like this:
impl Stream for SomeStream {
type Item = String;
type Error = Box<dyn std::error::Error + Send + Sync>; // generic error
fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
let delay = self.delay.get_or_insert_with(|| {
let when = Instant::now() + Duration::from_millis(1000);
Delay::new(when)
});
match delay.poll() {
Ok(Async::Ready(value)) => {
self.delay = None;
Ok(Async::Ready(Some("Hello".to_string())))
},
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => Err(err.into()),
}
}
}
Or, even better, using the try_ready! macro, which makes the return of errors and NotReady signals with less boilerplate.
fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
let delay = self.delay.get_or_insert_with(|| {
let when = Instant::now() + Duration::from_millis(1000);
Delay::new(when)
});
try_ready!(delay.poll());
// tick!
self.delay = None;
Ok(Async::Ready(Some("Hello".to_string())))
}
(Playground)

How to correctly exit the thread blocking on mpsc::Receiver

impl A {
fn new() -> (A, std::sync::mpsc::Receiver<Data>) {
let (sender, receiver) = std::sync::mpsc::channel();
let objA = A { sender: sender, }; // A spawns threads, clones and uses sender etc
(objA, receiver)
}
}
impl B {
fn new() -> B {
let (objA, receiver) = A::new();
B {
a: objA,
join_handle: Some(std::thread::spwan(move || {
loop {
match receiver.recv() {
Ok(data) => /* Do Something, inform main thread etc */,
Err(_) => break,
}
}
})),
}
}
}
impl Drop for B {
fn drop(&mut self) {
// Want to do something like "sender.close()/receiver.close()" etc so that the following
// thread joins. But there is no such function. How do i break the following thread ?
self.join_handle().take().unwrap().join().unwrap();
}
}
Is there a way to cleanly exit under such a circumstance ? The thing is that when either receiver or sender is dropped the other sniffs this and gives an error. In case of receiver it will be woken up and will yield an error in which case i am breaking out of the infinite and blocking loop above. However how do i do that explicitly using this very property of channels, without resorting to other flags in conjunction with try_recv()etc., and cleanly exit my thread deterministically?
Why not sending a specific message to shut this thread? I do not know what is your data but most of the time it may be an enum and adding a enum variant like 'MyData::Shutdown' in your receive you can simply break out of the loop.
You can wrap the a field of your B type in an Option. This way in the Drop::drop method you can do drop(self.a.take()) which will replace the field with a None and drop the sender. This closes the channel and your thread can now be properly joined.
You can create a new channel and swap your actual sender out with the dummy-sender. Then you can drop your sender and therefor join the thread:
impl Drop for B {
fn drop(&mut self) {
let (s, _) = channel();
drop(replace(&mut self.a.sender, s));
self.join_handle.take().unwrap().join().unwrap();
}
}
Try it out in the playpen: http://is.gd/y7A9L0
I don't know what the overhead of creating and immediately dropping a channel is, but it's not free and unlikely to be optimized out (There's an Arc in there).
on a side-note, Your infinite loop with a match on receiver.recv() could be replaced by a for loop using the Receiver::iter method:
for _ in receiver.iter() {
// do something with the value
}

Resources