Reputation: 2176
I have a video player that plays a stream and should return whenever the video producer, the decoder or the renderer fails
pub async fn play_video(s: &MyStream) -> Result<(), Error> {
tokio::select! {
r = s.video_producer.run() => {
Ok(r?)
}
r = s.decoder.run() => {
Ok(r?)
}
//Renderer would go here, but it can't cause it's not `Send`
}
}
However, since a Renderer
usually has to be on a thread and not move to another, it's not Send
, so it cannot be used inside an async call.
My solution was to spawn a thread and create the renderer inside the thread, so it never has to be moved from threads:
let renderer_join_handle = std::thread::spawn(move || {
//...
})
I get a JoinHandle<Result<(),RendererError>>
for which I can detect errors and return. However, it's not like the tokio select where it returns immediately. Is there a way to continuously poll this JoinHandle in the tokio select, thus async? Or is there a better solution that I'm not aware?
Basically I wanted the Renderer to be like the video producer and the decoder, and return its error on the tokio select.
Upvotes: 0
Views: 1664
Reputation: 71055
Don't use std::thread::spawn()
. Use tokio::task::spawn_blocking()
.
Alternatively, if the rendered must be on its own thread, you can create a oneshot async channel via tokio::sync::oneshot::channel()
. send()
the result to it from the rendered thread when it is finished, and receive from it by the select!
.
Upvotes: 1