Hello Rust community! I'm trying to learn Rust by writing a small tool that spawns processes and monitors their status. Here's the gist of it:
use std::thread::sleep;
use std::time::Duration;
use std::process::Command;
use std::process::Child;
use std::collections::HashMap;
type AgentMap = HashMap<String, Child>;
fn main() {
let mut agents = AgentMap::new();
let mut child = Command::new("sleep")
.arg("5")
.spawn()
.expect("ls command failed to start");
agents.insert("a".to_string(), &child);
loop {
for (agent, &process) in agents.iter() {
let timeout = Duration::from_secs(1);
sleep(timeout);
match process.try_wait() {
Ok(Some(status)) => println!("Exited with status {}", status),
Ok(None) => println!("timeout, process is still alive: {}", agent),
Err(e) => println!("Error waiting: {}", e),
}
}
}
}
Unfortunately, I'm getting the fllowing error:
error[E0596]: cannot borrow `process` as mutable, as it is not declared as mutable
Is this because a Child instance cannot be stored within a HashMap?
No. It's because wait requires mutable access, but you are only requesting immutable borrows. Use .iter_mut() instead, and do not put an immutable reference in the map. (Immutability in Rust is transitive – you can't mutate through an immutable reference to a mutable reference.)
oh, you're also storing shared (immutable) references in the map. You would need to either store &mut references or the Child objects by value for this to work.
it's not a "dangling reference" issue, just a logic one - right now, once a Child has exited, you'll keep getting a log message once every second with the status (and you never exit the outer loop). It depends what your intention was.
All of this can be inferred from the signature of the try_wait method (which can be found in the official documentation of the standard library) and the relevant parts of the Book (wrt. transitive immutability). The transitive immutability part is very basic; you should have already come across it if you read the Book.
There cannot be any dangling references; that would only be possible if you had used unsafe. Rust statically and reliably prevents memory errors like that, as long as you stick to the safe subset (which you normally should – there are no reasons to use unsafe while you are learning the language, and its use is hardly ever warranted outside interacting with FFI even for seasoned users).