Expand description
Fast, Bounded, Lossy broadcast channel with no_std
support.
This is implemented with ring buffer and atomic operations, it may be considered lock-free,
as we don’t use Lock
premitive, but the implementation may spin waiting for a contending
writer/reader to finish accessing a specific node. Its very rare, but
maybe I won’t call it lock-free
in the strict sense.
The API of the blinkcast
is similar to that of the std::sync::mpsc
channels.
However, there are some differences:
- It allows for multiple consumers (receivers) and multiple prodocuers (senders).
- The channel broadcasts every send to every consumer.
- Lossy, the sender will overwrite old data, so receivers must be quick or they will lose the old data (don’ t blink).
- Implemented for
no_std
environments.
The data sent must implment Clone
, because it will be kept in the buffer, and readers can read it multiple times.
The original object will remain in the buffer until its overwritten, at that point it will be dropped.
Thus be careful if the value is a large allocation for example big Arc
. One of the clones (original) will
be kept by the buffer and will result in a delayed deallocation if that was not expected by the user.
See issue #1
Example
Single sender multiple receivers
use blinkcast::alloc::channel;
let (sender, mut receiver1) = channel::<i32>(4);
sender.send(1);
sender.send(2);
let mut receiver2 = receiver1.clone();
assert_eq!(receiver1.recv(), Some(1));
assert_eq!(receiver1.recv(), Some(2));
assert_eq!(receiver1.recv(), None);
assert_eq!(receiver2.recv(), Some(1));
assert_eq!(receiver2.recv(), Some(2));
assert_eq!(receiver2.recv(), None);
Multiple senders multiple receivers
use blinkcast::alloc::channel;
use std::thread;
let (sender1, mut receiver1) = channel::<i32>(100);
let sender2 = sender1.clone();
let t1 = thread::spawn(move || {
for i in 0..50 {
sender1.send(i);
}
});
let t2 = thread::spawn(move || {
for i in 0..50 {
sender2.send(i);
}
});
t1.join().unwrap();
t2.join().unwrap();
let mut receiver2 = receiver1.clone();
let mut sum1 = 0;
let mut sum2 = 0;
for i in 0..100 {
let v1 = receiver1.recv().unwrap();
let v2 = receiver2.recv().unwrap();
sum1 += v1;
sum2 += v2;
assert_eq!(v1, v2);
}
assert_eq!(sum1, 49 * 50);
assert_eq!(sum2, 49 * 50);
Another example using the static_mem
module (no allocation)
use blinkcast::static_mem::Sender;
let sender = Sender::<i32, 4>::new();
let mut receiver1 = sender.new_receiver();
sender.send(1);
sender.send(2);
let mut receiver2 = receiver1.clone();
assert_eq!(receiver1.recv(), Some(1));
assert_eq!(receiver1.recv(), Some(2));
assert_eq!(receiver1.recv(), None);
assert_eq!(receiver2.recv(), Some(1));
assert_eq!(receiver2.recv(), Some(2));
assert_eq!(receiver2.recv(), None);
Modules
- A channel implemented with heap allocated buffers (require
alloc
feature). - A channel implemented with static memory.
Constants
- The maximum length of the buffer allowed on this platform It will be
2^16 - 1
on 32bit platforms and2^32 - 1
on 64bit platforms