crossbeam_channel

Macro select

source
macro_rules! select {
    ($($tokens:tt)*) => { ... };
}
Expand description

Selects from a set of channel operations.

This macro allows you to define a set of channel operations, wait until any one of them becomes ready, and finally execute it. If multiple operations are ready at the same time, a random one among them is selected (i.e. the unbiased selection). Use select_biased! for the biased selection.

It is also possible to define a default case that gets executed if none of the operations are ready, either right away or for a certain duration of time.

An operation is considered to be ready if it doesn’t have to block. Note that it is ready even when it will simply return an error because the channel is disconnected.

The select! macro is a convenience wrapper around Select. However, it cannot select over a dynamically created list of channel operations.

§Examples

Block until a send or a receive operation is selected:

use crossbeam_channel::{select, unbounded};

let (s1, r1) = unbounded();
let (s2, r2) = unbounded();
s1.send(10).unwrap();

// Since both operations are initially ready, a random one will be executed.
select! {
    recv(r1) -> msg => assert_eq!(msg, Ok(10)),
    send(s2, 20) -> res => {
        assert_eq!(res, Ok(()));
        assert_eq!(r2.recv(), Ok(20));
    }
}

Select from a set of operations without blocking:

use std::thread;
use std::time::Duration;
use crossbeam_channel::{select, unbounded};

let (s1, r1) = unbounded();
let (s2, r2) = unbounded();

thread::spawn(move || {
    thread::sleep(Duration::from_secs(1));
    s1.send(10).unwrap();
});
thread::spawn(move || {
    thread::sleep(Duration::from_millis(500));
    s2.send(20).unwrap();
});

// None of the operations are initially ready.
select! {
    recv(r1) -> msg => panic!(),
    recv(r2) -> msg => panic!(),
    default => println!("not ready"),
}

Select over a set of operations with a timeout:

use std::thread;
use std::time::Duration;
use crossbeam_channel::{select, unbounded};

let (s1, r1) = unbounded();
let (s2, r2) = unbounded();

thread::spawn(move || {
    thread::sleep(Duration::from_secs(1));
    s1.send(10).unwrap();
});
thread::spawn(move || {
    thread::sleep(Duration::from_millis(500));
    s2.send(20).unwrap();
});

// None of the two operations will become ready within 100 milliseconds.
select! {
    recv(r1) -> msg => panic!(),
    recv(r2) -> msg => panic!(),
    default(Duration::from_millis(100)) => println!("timed out"),
}

Optionally add a receive operation to select! using never:

use std::thread;
use std::time::Duration;
use crossbeam_channel::{select, never, unbounded};

let (s1, r1) = unbounded();
let (s2, r2) = unbounded();

thread::spawn(move || {
    thread::sleep(Duration::from_secs(1));
    s1.send(10).unwrap();
});
thread::spawn(move || {
    thread::sleep(Duration::from_millis(500));
    s2.send(20).unwrap();
});

// This receiver can be a `Some` or a `None`.
let r2 = Some(&r2);

// None of the two operations will become ready within 100 milliseconds.
select! {
    recv(r1) -> msg => panic!(),
    recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
}

To optionally add a timeout to select!, see the example for never.