Skip to content

Commit dcef449

Browse files
committed
discuss deadlocks in the std::io::pipe() example
1 parent c8bda74 commit dcef449

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

library/std/src/io/pipe.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,44 @@ use crate::sys_common::{FromInner, IntoInner};
3838
/// > not rely on a particular capacity: an application should be designed so that a reading process
3939
/// > consumes data as soon as it is available, so that a writing process does not remain blocked.
4040
///
41-
/// # Examples
41+
/// # Example
4242
///
4343
/// ```no_run
4444
/// # #[cfg(miri)] fn main() {}
4545
/// # #[cfg(not(miri))]
4646
/// # fn main() -> std::io::Result<()> {
47+
/// use std::io::{Read, Write, pipe};
4748
/// use std::process::Command;
48-
/// use std::io::{pipe, Read, Write};
49-
/// let (ping_rx, mut ping_tx) = pipe()?;
50-
/// let (mut pong_rx, pong_tx) = pipe()?;
49+
/// let (ping_reader, mut ping_writer) = pipe()?;
50+
/// let (mut pong_reader, pong_writer) = pipe()?;
5151
///
52-
/// // Spawn a process that echoes its input.
53-
/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
52+
/// // Spawn a child process that echoes its input.
53+
/// let mut echo_command = Command::new("cat");
54+
/// echo_command.stdin(ping_reader);
55+
/// echo_command.stdout(pong_writer);
56+
/// let mut echo_child = echo_command.spawn()?;
5457
///
55-
/// ping_tx.write_all(b"hello")?;
56-
/// // Close to unblock echo_server's reader.
57-
/// drop(ping_tx);
58+
/// // Send input to the child process. Note that because we're writing all the input before we
59+
/// // read any output, this could deadlock if the child's input and output pipe buffers both
60+
/// // filled up. Those buffers are usually at least a few KB, so "hello" is fine, but for longer
61+
/// // inputs we'd need to read and write at the same time, e.g. using threads.
62+
/// ping_writer.write_all(b"hello")?;
63+
///
64+
/// // `cat` exits when it reads EOF from stdin, but that can't happen while any ping writer
65+
/// // remains open. We need to drop our ping writer, or read_to_string will deadlock below.
66+
/// drop(ping_writer);
67+
///
68+
/// // The pong reader can't report EOF while any pong writer remains open. Our Command object is
69+
/// // holding a pong writer, and again read_to_string will deadlock if we don't drop it.
70+
/// drop(echo_command);
5871
///
5972
/// let mut buf = String::new();
60-
/// // Block until echo_server's writer is closed.
61-
/// pong_rx.read_to_string(&mut buf)?;
73+
/// // Block until `cat` closes its stdout (a pong writer).
74+
/// pong_reader.read_to_string(&mut buf)?;
6275
/// assert_eq!(&buf, "hello");
6376
///
64-
/// echo_server.wait()?;
77+
/// // At this point we know `cat` has exited, but we still need to wait to clean up the "zombie".
78+
/// echo_child.wait()?;
6579
/// # Ok(())
6680
/// # }
6781
/// ```

0 commit comments

Comments
 (0)