Process stdin write_all in loop

Hi Guys,

I have a child process stdin like this:

let mut stdin = child.stdin.take().unwrap();

If I try to write to that subprocess like this, it works:

    thread::spawn(move || {
        stdin.write_all(b"2").unwrap();
    });

but if I use a loop, then it does not work:

    thread::spawn(move || {
        stdin.write_all(b"2").unwrap();
        loop {}
    });

What am I missing?

This might be a known issue where LLVM assumes that code never loops forever without doing things such as IO. Try putting a sleep inside the loop.

Haven’t tested it but it might be because it’s not flushing.

A normal implementor of Write will usually also call flush on drop, try if inserting stdin.flush() before the loop helps.

1 Like

I suspect that @steffahn has the correct answer here.

For future reference, it’s usually easier to help with your problems if you describe what the buggy code is doing in addition to what you expect. Here, that could be something like:

When I add a loop, it stops printing anything.

This lets us focus on the problem you’re actually having instead of all the possble problems you might have. I, for example, immediately started looking for possible sources of compile errors.

It also makes it easier for others having the same problem to find this thread in the future.

Here is my code:

fn start_listener(child: &mut Child, sender: Sender<String>) -> JoinHandle<()> {
    let mut stdin = child.stdin.take().unwrap();
    let stdout = child.stdout.take().unwrap();
    let mut f = BufReader::new(stdout);
    return thread::spawn(move || loop {
        let mut buf = String::new();
        match f.read_line(&mut buf) {
            Ok(_) => {
                stdin.write_all("2".as_bytes()).unwrap();
                sender.send(buf).unwrap();
            }
            Err(e) => println!("an error!: {:?}", e),
        }
    });
}

I have a sub-process, which is running in the background continuously, I have a function which takes a mutable reference to this process and in a thread it loops it over, to check for new lines. If there is a new line, I want to send back an stdin.

In the code above, the code compiles, the childprocess works, and when stdout occures, it sends the content via the sender channel. But the stdin.write_all() does not work at all. There is no error message also.

@alice what do you think?

Btw, I checked the flush, and it seems to me, that it does nothing :open_mouth:

#[stable(feature = "process", since = "1.0.0")]
impl Write for ChildStdin {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.write(buf)
    }

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.inner.write_vectored(bufs)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

What do you mean with "doesn't work"? Does it seem like it does nothing? How do you know that the process received nothing?

Maybe the child is still waiting for you to write a newline, or to close the stdin pipe?

2 Likes

@alice grrrr, you made my day :heart: . I changed write_all(b"2") to write_all(b"2\n") and it works. So the new line solved it.

I am kind of new to the process stdin and stdout, and it was soo confusing to not understand why does not happening anything.

I knew something wrong, is because the child process did not receive the content. But if I just tested it without the thread part, it worked.

It also strange, that if I do not use a new line, but nor the thread part, it works. If I use it inside a thread with a loop, then I need to apply the new line character. Do you understand why?

There’s two ways that a program can know that a line of input is complete: it can see a newline character or the input stream can be closed. The loop holds the stream open so that it can be used again later, which means you need to use the newline method.

2 Likes

This is a wonderful world. Thank you guys.

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.