Skip to content
CryoCryo home
Stdlibsync

mpsc

import std::sync::mpsc; · source

channel

function channel<T>() -> Receiver<T>;

channel<T>() returns the owning Receiver<T>; mint producers from it with rx.sender(). Each Sender<T> is independently owned and movable into its own thread, and cloneable for further fan-out. Values of any type — including owned data like String — move through an unbounded FIFO queue.

import std::sync::mpsc;
import std::thread;

mut rx: mpsc::Receiver<i32> = mpsc::channel<i32>();
const tx: mpsc::Sender<i32> = rx.sender();

const h = thread::spawn<mpsc::Sender<i32>, i32>(tx, (s: mpsc::Sender<i32>) -> i32 {
    mut snd: mpsc::Sender<i32> = s;
    snd.send(42);
    snd.close();
    return 0;
});

match (rx.recv()) {
    Result::Ok(v)  => { use(v); }
    Result::Err(_) => { }
}
h.join();

Sender<T>

type struct Sender<T> {
    inner: ChannelInner<T>*;

    send(&this, value: T) -> Result<(), SendError<T>>;
    clone(&this) -> Sender<T>;
    close(mut this) -> void;
}

send moves a value into the queue. clone() mints another producer; close() consumes the sender and is equivalent to dropping it early.

Receiver<T>

type struct Receiver<T> {
    inner: ChannelInner<T>*;

    sender(&this) -> Sender<T>;
    recv(&this) -> Result<T, RecvError>;
    try_recv(&this) -> Result<T, TryRecvError>;
}

recv() blocks; try_recv() returns Err(Empty) immediately when nothing is queued. sender() mints producers from the receiver, which is why channel returns only the receiver.

The errors

type struct SendError<T> {
    value: T;
}
type enum RecvError {
    Disconnected;
}
type enum TryRecvError {
    Empty;
    Disconnected;
}

Disconnection

When every Sender has been dropped, a blocked recv() returns Err(RecvError::Disconnected) and try_recv() returns Err(TryRecvError::Disconnected).

When the Receiver is dropped, send() returns Err(SendError) handing the value back, rather than queueing into a channel nobody will drain.

Underneath, a heap inner holds a mutex and condition variable guarding a raw singly-linked node queue, plus a live-sender count and a total-handle refcount; the inner is reclaimed when the last handle of either kind drops. Values move out of dequeued nodes through raw pointers, so the move-checker sees each as a clean transfer — no aliasing, no double free.

Trait implementations

implement<T> trait Drop for struct Sender<T>

implement<T> trait Drop for struct Receiver<T>
where T: Drop

Receiver::drop drains and drops whatever is still queued, which is why it carries the T: Drop bound.