Macro crossbeam_channel::select [−][src]
macro_rules! select { ($($case:ident $(($($args:tt)*))* => $body:expr $(,)*)*) => { ... }; ($($tokens:tt)*) => { ... }; }
Waits on a set of channel operations.
This macro allows declaring a set of channel operations and blocking until any one of them
becomes ready. Finally, one of the operations is executed. If multiple operations are ready at
the same time, a random one is chosen. It is also possible to declare a default case that
gets executed if none of the operations are initially ready.
Receiving
Receiving a message from two channels, whichever becomes ready first:
use std::thread; use crossbeam_channel as channel; let (s1, r1) = channel::unbounded(); let (s2, r2) = channel::unbounded(); thread::spawn(move || s1.send("foo")); thread::spawn(move || s2.send("bar")); // Only one of these two receive operations will be executed. select! { recv(r1, msg) => assert_eq!(msg, Some("foo")), recv(r2, msg) => assert_eq!(msg, Some("bar")), }
Sending
Waiting on a send and a receive operation:
use std::thread; use crossbeam_channel as channel; let (s1, r1) = channel::unbounded(); let (s2, r2) = channel::unbounded(); s1.send("foo"); // Since both operations are initially ready, a random one will be executed. select! { recv(r1, msg) => assert_eq!(msg, Some("foo")), send(s2, "bar") => assert_eq!(r2.recv(), Some("bar")), }
Default case
A special kind of case is default, which gets executed if none of the operations can be
executed, i.e. they would block:
use std::thread; use std::time::{Duration, Instant}; use crossbeam_channel as channel; let (s, r) = channel::unbounded(); thread::spawn(move || { thread::sleep(Duration::from_secs(1)); s.send("foo"); }); // Don't block on the receive operation. select! { recv(r) => panic!(), default => println!("The message is not yet available."), }
Iterators
It is possible to have arbitrary iterators of senders or receivers in a single send or recv
case:
use std::thread; use std::time::{Duration, Instant}; use crossbeam_channel as channel; let (s1, r1) = channel::unbounded(); let (s2, r2) = channel::unbounded(); s1.send("foo"); s2.send("bar"); let receivers = vec![r1, r2]; // Both receivers are initially ready so one of the two receive operations // will be chosen randomly. select! { // The third argument to `recv` is optional and is assigned a // reference to the receiver the message was received from. recv(receivers, msg, from) => { for (i, r) in receivers.iter().enumerate() { if r == from { println!("Received {:?} from the {}-th receiver.", msg, i); } } } }
Syntax
An invocation of select! consists of a list of cases. Consecutive cases are delimited by a
comma, but it's not required if the preceding case has a block expression (the syntax is very
similar to match statements).
The following invocation illustrates all the possible forms cases can take:
select! { recv(r1) => body1, recv(r2, msg2) => body2, recv(r3, msg3, from3) => body3, send(s4, msg4) => body4, send(s5, msg5, into5) => body5, default => body6, }
Input expressions: r1, r2, r3, s4, s5, msg4, msg5, body1, body2, body3,
body4, body5, body6
Output patterns: msg2, msg3, msg4, msg5, from3, into5
Types of expressions and patterns (generic over types A, B, C, D, E, and F):
r1: one ofReceiver<A>,&Receiver<A>, orimpl IntoIterator<Item = &Receiver<A>>r2: one ofReceiver<B>,&Receiver<B>, orimpl IntoIterator<Item = &Receiver<B>>r3: one ofReceiver<C>,&Receiver<C>, orimpl IntoIterator<Item = &Receiver<C>>s4: one ofSender<D>,&Sender<D>, orimpl IntoIterator<Item = &Sender<D>>s5: one ofSender<E>,&Sender<E>, orimpl IntoIterator<Item = &Sender<E>>msg2:Option<B>msg3:Option<C>msg4:Dmsg5:Efrom3:&Receiver<C>into5:&Sender<E>body1,body2,body3,body4,body5,body6:F
Pattern from3 is bound to the receiver in r3 from which msg3 was received.
Pattern into5 is bound to the sender in s5 into which msg5 was sent.
There can be at most one default case.
Execution
- All sender and receiver arguments (
r1,r2,r3,s4, ands5) are evaluated. - If any of the
recvorsendoperations are ready, one of them is executed. If multiple operations are ready, a random one is chosen. - If none of the
recvandsendoperations are ready, thedefaultcase is executed. If there is nodefaultcase, the current thread is blocked until an operation becomes ready. - If a
recvoperation gets executed, the message pattern (msg2ormsg3) is bound to the received message, and the receiver pattern (from3) is bound to the receiver from which the message was received. - If a
sendoperation gets executed, the message (msg4ormsg5) is evaluated and sent into the channel. Then, the sender pattern (into5) is bound to the sender into which the message was sent. - Finally, the body (
body1,body2,body3,body4,body5, orbody6) of the executed case is evaluated. The wholeselect!invocation evaluates to that expression.
Note: If evaluation of msg4 or msg5 panics, the process will be aborted because it's
impossible to recover from such panics. All the other expressions are allowed to panic,
however.