Module std::commUnstable [-]  [+] [src]

Communication primitives for concurrent tasks

Rust makes it very difficult to share data among tasks to prevent race conditions and to improve parallelism, but there is often a need for communication between concurrent tasks. The primitives defined in this module are the building blocks for synchronization in rust.

This module provides message-based communication over channels, concretely defined among three types:

A Sender or SyncSender is used to send data to a Receiver. Both senders are clone-able such that many tasks can send simultaneously to one receiver. These channels are task blocking, not thread blocking. This means that if one task is blocked on a channel, other tasks can continue to make progress.

Rust channels come in one of two flavors:

  1. An asynchronous, infinitely buffered channel. The channel() function will return a (Sender, Receiver) tuple where all sends will be asynchronous (they never block). The channel conceptually has an infinite buffer.

  2. A synchronous, bounded channel. The sync_channel() function will return a (SyncSender, Receiver) tuple where the storage for pending messages is a pre-allocated buffer of a fixed size. All sends will be synchronous by blocking until there is buffer space available. Note that a bound of 0 is allowed, causing the channel to become a "rendezvous" channel where each sender atomically hands off a message to a receiver.

Panic Propagation

In addition to being a core primitive for communicating in rust, channels are the points at which panics are propagated among tasks. Whenever the one half of channel is closed, the other half will have its next operation panic!. The purpose of this is to allow propagation of panics among tasks that are linked to one another via channels.

There are methods on both of senders and receivers to perform their respective operations without panicking, however.

Example

Simple usage:

fn main() { use std::thread::Thread; // Create a simple streaming channel let (tx, rx) = channel(); Thread::spawn(move|| { tx.send(10i); }).detach(); assert_eq!(rx.recv(), 10i); }
use std::thread::Thread;

// Create a simple streaming channel
let (tx, rx) = channel();
Thread::spawn(move|| {
    tx.send(10i);
}).detach();
assert_eq!(rx.recv(), 10i);

Shared usage:

fn main() { use std::thread::Thread; // Create a shared channel that can be sent along from many threads // where tx is the sending half (tx for transmission), and rx is the receiving // half (rx for receiving). let (tx, rx) = channel(); for i in range(0i, 10i) { let tx = tx.clone(); Thread::spawn(move|| { tx.send(i); }).detach() } for _ in range(0i, 10i) { let j = rx.recv(); assert!(0 <= j && j < 10); } }
use std::thread::Thread;

// Create a shared channel that can be sent along from many threads
// where tx is the sending half (tx for transmission), and rx is the receiving
// half (rx for receiving).
let (tx, rx) = channel();
for i in range(0i, 10i) {
    let tx = tx.clone();
    Thread::spawn(move|| {
        tx.send(i);
    }).detach()
}

for _ in range(0i, 10i) {
    let j = rx.recv();
    assert!(0 <= j && j < 10);
}

Propagating panics:

fn main() { // The call to recv() will panic!() because the channel has already hung // up (or been deallocated) let (tx, rx) = channel::<int>(); drop(tx); rx.recv(); }
// The call to recv() will panic!() because the channel has already hung
// up (or been deallocated)
let (tx, rx) = channel::<int>();
drop(tx);
rx.recv();

Synchronous channels:

fn main() { use std::thread::Thread; let (tx, rx) = sync_channel::<int>(0); Thread::spawn(move|| { // This will wait for the parent task to start receiving tx.send(53); }).detach(); rx.recv(); }
use std::thread::Thread;

let (tx, rx) = sync_channel::<int>(0);
Thread::spawn(move|| {
    // This will wait for the parent task to start receiving
    tx.send(53);
}).detach();
rx.recv();

Reading from a channel with a timeout requires to use a Timer together with the channel. You can use the select! macro to select either and handle the timeout case. This first example will break out of the loop after 10 seconds no matter what:

fn main() { use std::io::timer::Timer; use std::time::Duration; let (tx, rx) = channel::<int>(); let mut timer = Timer::new().unwrap(); let timeout = timer.oneshot(Duration::seconds(10)); loop { select! { val = rx.recv() => println!("Received {}", val), () = timeout.recv() => { println!("timed out, total time was more than 10 seconds"); break; } } } }
use std::io::timer::Timer;
use std::time::Duration;

let (tx, rx) = channel::<int>();
let mut timer = Timer::new().unwrap();
let timeout = timer.oneshot(Duration::seconds(10));

loop {
    select! {
        val = rx.recv() => println!("Received {}", val),
        () = timeout.recv() => {
            println!("timed out, total time was more than 10 seconds");
            break;
        }
    }
}

This second example is more costly since it allocates a new timer every time a message is received, but it allows you to timeout after the channel has been inactive for 5 seconds:

fn main() { use std::io::timer::Timer; use std::time::Duration; let (tx, rx) = channel::<int>(); let mut timer = Timer::new().unwrap(); loop { let timeout = timer.oneshot(Duration::seconds(5)); select! { val = rx.recv() => println!("Received {}", val), () = timeout.recv() => { println!("timed out, no message received in 5 seconds"); break; } } } }
use std::io::timer::Timer;
use std::time::Duration;

let (tx, rx) = channel::<int>();
let mut timer = Timer::new().unwrap();

loop {
    let timeout = timer.oneshot(Duration::seconds(5));

    select! {
        val = rx.recv() => println!("Received {}", val),
        () = timeout.recv() => {
            println!("timed out, no message received in 5 seconds");
            break;
        }
    }
}

Reexports

pub use self::TryRecvError::*;
pub use self::TrySendError::*;

Structs

Handle

A handle to a receiver which is currently a member of a Select set of receivers. This handle is used to keep the receiver in the set as well as interact with the underlying receiver.

Messages

An iterator over messages on a receiver, this iterator will block whenever next is called, waiting for a new message, and None will be returned when the corresponding channel has hung up.

Receiver

The receiving-half of Rust's channel type. This half can only be owned by one task

Select

The "receiver set" of the select interface. This structure is used to manage a set of receivers which are being selected over.

Sender

The sending-half of Rust's asynchronous channel type. This half can only be owned by one task, but it can be cloned to send to other tasks.

SyncSender

The sending-half of Rust's synchronous channel type. This half can only be owned by one task, but it can be cloned to send to other tasks.

Enums

TryRecvError

This enumeration is the list of the possible reasons that try_recv could not return data when called.

TrySendError

This enumeration is the list of the possible error outcomes for the SyncSender::try_send method.

Functions

channel

Creates a new asynchronous channel, returning the sender/receiver halves.

sync_channel

Creates a new synchronous, bounded channel.