std::process::Child cannot be stored inside a HashMap?

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.)

Accordingly, this compiles.

1 Like

I think you want this line instead:

for (agent, process) in agents.iter_mut() {

However, you should also ask yourself what you expect to happen when the process exits - should it be removed from the Map or not?

1 Like

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.

1 Like

Thank you. Would you recommend any specific literature to avoid mistakes like these?

Thank you! Not sure if I understand your question: are you implying that I should remove from the map to avoid dangling references?

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.

1 Like

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).

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.