pipe in std::io - Rust
Description: Creates an anonymous pipe.

## pipe

# Function pipe

1.87.0 · Source

    pub fn pipe() -> Result<(PipeReader, PipeWriter)>

Expand description

Creates an anonymous pipe.

## §Behavior

A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is typically used to communicate between two or more separate processes, as there are better, faster ways to communicate within a single process.

In particular:

- A read on a `PipeReader` blocks until the pipe is non-empty.
- A write on a `PipeWriter` blocks when the pipe is full.
- When all copies of a `PipeWriter` are closed, a read on the corresponding `PipeReader` returns EOF.
- `PipeWriter` can be shared, and multiple processes or threads can write to it at once, but writes (above a target-specific threshold) may have their data interleaved.
- `PipeReader` can be shared, and multiple processes or threads can read it at once. Any given byte will only get consumed by one reader. There are no guarantees about data interleaving.
- Portable applications cannot assume any atomicity of messages larger than a single byte.

## §Platform-specific behavior

This function currently corresponds to the `pipe` function on Unix and the `CreatePipe` function on Windows.

Note that this may change in the future.

## §Capacity

Pipe capacity is platform dependent. To quote the Linux man page:

> Different implementations have different limits for the pipe capacity. Applications should not rely on a particular capacity: an application should be designed so that a reading process consumes data as soon as it is available, so that a writing process does not remain blocked.

## §Example

    use std::io::{Read, Write, pipe};
    use std::process::Command;
    let (ping_reader, mut ping_writer) = pipe()?;
    let (mut pong_reader, pong_writer) = pipe()?;

    // Spawn a child process that echoes its input.
    let mut echo_command = Command::new("cat");
    echo_command.stdin(ping_reader);
    echo_command.stdout(pong_writer);
    let mut echo_child = echo_command.spawn()?;

    // Send input to the child process. Note that because we're writing all the input before we
    // read any output, this could deadlock if the child's input and output pipe buffers both
    // filled up. Those buffers are usually at least a few KB, so "hello" is fine, but for longer
    // inputs we'd need to read and write at the same time, e.g. using threads.
    ping_writer.write_all(b"hello")?;

    // `cat` exits when it reads EOF from stdin, but that can't happen while any ping writer
    // remains open. We need to drop our ping writer, or read_to_string will deadlock below.
    drop(ping_writer);

    // The pong reader can't report EOF while any pong writer remains open. Our Command object is
    // holding a pong writer, and again read_to_string will deadlock if we don't drop it.
    drop(echo_command);

    let mut buf = String::new();
    // Block until `cat` closes its stdout (a pong writer).
    pong_reader.read_to_string(&mut buf)?;
    assert_eq!(&buf, "hello");

    // At this point we know `cat` has exited, but we still need to wait to clean up the "zombie".
    echo_child.wait()?;