admin管理员组

文章数量:1332108

I was building an audio-client on rodio, when i faced this issue. Thing is - as a common player i must be able to both react to track finishing, or commands (signals) coming from user. But the rodio's Sink structure (which is the root of audio handling) provides us with only one method suited for the task - sleep_until_end().

So i have decided to use select! from tokio, and create two async functions, first one waits for a signal from an mpsc channel, second one just sleeps until the end of the track, and after it is awakened - returns a Finished signal.

The problem is - select! from tokio can't work properly if one of the branches is thread-blocking, since it runs branches concurently, but not in paralel. And since sleep_until_end() is a thread_blocking method - i have to use it in spawn method and then use the join_handle in select!.

For that, i have to borrow the sink value from the client (self), since i can't either move or clone the Sink structure. And if i understand it correctly, it shouldn't be a problem: if blocking_task was the first one to complete - the reference is free to go, and we don't need to borrow it anymore; if the recv channel was faster - the other branch simply drops, which again - drops the reference, which means that borrow doesn't exist anymore.

But it's either me, or rustc, who can't understand how this code is supposed to work.

async fn listen_for_signal(recv: &mut UnboundedReciever<Signal>) -> Option<Signal> {
        recv.recv().await
    }

async fn listen(&mut self, recv: &mut UnboundedReciever<Signal>)
        loop {
            let next = {  
                let blocking_task = tokio::task::spawn_blocking(|| {
                    self.current.sleep_until_end();
                });
                let n = tokio::select! {
                    v = listen_for_signal(recv)=>v,
                    _ = blocking_task=> Some(Signal::Finished),
                };
                n
            };
            if let Some(s) = next {
                self.handle_signal(s);
            } else {
                break;
            }
        }
    }

Rustc compiler throws an error, borrowed data escapes outside of method self escapes the method body here (inside spawn_blocking).

Maybe there is a workaround with Arc/Pin/etc (i don't know, i'm bad at rust async). Please help

本文标签: asynchronousShare data for an async blockwithout it escaping the scope in rustStack Overflow