Spawn() is a blocking call? how to make it non-blocking?

judging by this piping example here Pipes - Rust By Example

use std::io::prelude::*;
use std::process::{Command, Stdio};

static PANGRAM: &'static str =
"the quick brown fox jumped over the lazy dog\n";

fn main() {
    // Spawn the `wc` command
    let process = match Command::new("wc")
                                .spawn() {
        Err(why) => panic!("couldn't spawn wc: {}", why),
        Ok(process) => process,

    // Write a string to the `stdin` of `wc`.
    // `stdin` has type `Option<ChildStdin>`, but since we know this instance
    // must have one, we can directly `unwrap` it.
    match process.stdin.unwrap().write_all(PANGRAM.as_bytes()) {
        Err(why) => panic!("couldn't write to wc stdin: {}", why),
        Ok(_) => println!("sent pangram to wc"),

    // Because `stdin` does not live after the above calls, it is `drop`ed,
    // and the pipe is closed.
    // This is very important, otherwise `wc` wouldn't start processing the
    // input we just sent.

    // The `stdout` field also has type `Option<ChildStdout>` so must be unwrapped.
    let mut s = String::new();
    match process.stdout.unwrap().read_to_string(&mut s) {
        Err(why) => panic!("couldn't read wc stdout: {}", why),
        Ok(_) => print!("wc responded with:\n{}", s),

the spawn() call should be non-blocking. But this is different from my observation:

    let process = Command::new("cargo")
        .args(&["run", "--bin", "gen"])
        .expect("failed to execute process");

this code will get stuck, even the subprocess shouldn't get stuck

for example, if I simply change spawn to output

    let output = Command::new("cargo")
        .args(&["run", "--bin", "gen"])
        .expect("failed to execute process");
    println!("after spawn");

the code can finish without any issues.

What do you mean by "non-blocking"? The spawn method doesn't wait for the process to finish, but it does wait for it to start.

And what do you mean by "getting stuck"? What exactly do you expect to happen, and what happens instead?

blocking (and getting stuck) means if I put

 println!("after spawn");

after the spawn(), I can't see any "after spawn" from the output. and the program never quits.

might be related to Create new child shell?

the program I want to run expects a piped input via stdin.

Note that according to the docs, Command::new will by default

  • Inherit stdin/stdout/stderr for spawn or status , but create pipes for output.

Maybe that's the relevant difference here?

here is another user with a similar problem

I'm not the only one seeing this.

I can’t reproduce this in either Windows or Linux with the simplest version of your program, so I think there’s something else going on:

use std::process::Command;

fn main() {
    let mut process = Command::new("cargo")
        .args(&["run", "--bin", "gen"])
        .expect("failed to execute process");
    println!("after spawn");
    let status = process.wait().expect("failed to wait for process");
    println!("after wait\n{}", status);


fn main() {
    println!("in child")

When I run this, I get:

% cargo run --bin testcmd
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/testcmd`
after spawn
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/gen`
in child
after wait
exit status: 0

If I was stuck like this, I'd try running the program with strace -f in order to see where it was getting stuck, like

strace -f target/debug/testcmd

There will be a lot of output, but the last lines should show where the programs got to.

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.