In my first ever use of tokio I have a bunch of async functions that spawn threads that should run forever. They have signatures like so:
async fn socket_listener_task(
mut tcp_listener: TcpListener,
serial_writer: SerialWriter,
mut clients: Clients,
) -> tokio::task::JoinHandle<()> {
tokio::spawn(async move {
loop {
// Do stuff...
}
})
}
If any of these threads should die so should my whole program. So I thought I would use tokio::select! to catch when any one terminates:
tokio::select! {
_ = nats_pinger(nc.clone()).await => {
println!("NATS pinger task failed");
}
_ = nats_subscriber(nc.clone(), serial_writer.clone()).await => {
println!("NATS subscriber task failed");
}
_ = socket_listener_task(tcp_listener, serial_writer.clone(), clients.clone()).await => {
println!("NATS socket listener task failed");
}
_ = serial_reader_task(serial_reader.clone(), clients.clone(), nc.clone()).await => {
println!("Serial reader task failed");
}
}
As soon as I put that in clippy threw a hissy fit with 12 warnings like so:
warning: unsequenced read of a variable
--> src/lib.rs:302:13
|
302 | _ = socket_listener_task(tcp_listener, serial_writer.clone(), clients.clone()).await => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: whether read occurs before this write depends on evaluation order
--> src/lib.rs:305:13
|
305 | _ = serial_reader_task(serial_reader.clone(), clients.clone(), nc.clone()).await => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
I read the suggested link. I get the idea of confusing order of operations. But I don't understand it here.
I can keep clippy happy by doing this:
// Run the threads!
let h1 = nats_pinger(nc.clone()).await;
let h2 = nats_subscriber(nc.clone(), serial_writer.clone()).await;
let h3 = socket_listener_task(tcp_listener, serial_writer.clone(), clients.clone()).await;
let h4 = serial_reader_task(serial_reader.clone(), clients.clone(), nc.clone()).await;
tokio::select! {
_ = h1 => {
println!("NATS pinger task failed");
}
_ = h2 => {
println!("NATS subscriber task failed");
}
_ = h3 => {
println!("NATS socket listener task failed");
}
_ = h4 => {
println!("Serial reader task failed");
}
}
But that seems yukky.
Any suggestions?