sync: implement Clone for broadcast::Receiver (#2933)

This commit is contained in:
Zephyr Shannon
2020-10-19 10:12:40 +02:00
committed by GitHub
parent e88e64bcc0
commit fb28caa90c
2 changed files with 28 additions and 15 deletions
+26 -14
View File
@@ -405,7 +405,8 @@ const MAX_RECEIVERS: usize = usize::MAX >> 2;
/// ///
/// The `Sender` can be cloned to `send` to the same channel from multiple /// The `Sender` can be cloned to `send` to the same channel from multiple
/// points in the process or it can be used concurrently from an `Arc`. New /// points in the process or it can be used concurrently from an `Arc`. New
/// `Receiver` handles are created by calling [`Sender::subscribe`]. /// `Receiver` handles can be cloned from an existing `Receiver` or created by
/// calling [`Sender::subscribe`].
/// ///
/// If all [`Receiver`] handles are dropped, the `send` method will return a /// If all [`Receiver`] handles are dropped, the `send` method will return a
/// [`SendError`]. Similarly, if all [`Sender`] handles are dropped, the [`recv`] /// [`SendError`]. Similarly, if all [`Sender`] handles are dropped, the [`recv`]
@@ -569,19 +570,7 @@ impl<T> Sender<T> {
/// ``` /// ```
pub fn subscribe(&self) -> Receiver<T> { pub fn subscribe(&self) -> Receiver<T> {
let shared = self.shared.clone(); let shared = self.shared.clone();
new_receiver(shared)
let mut tail = shared.tail.lock();
if tail.rx_cnt == MAX_RECEIVERS {
panic!("max receivers");
}
tail.rx_cnt = tail.rx_cnt.checked_add(1).expect("overflow");
let next = tail.pos;
drop(tail);
Receiver { shared, next }
} }
/// Returns the number of active receivers /// Returns the number of active receivers
@@ -671,6 +660,22 @@ impl<T> Sender<T> {
} }
} }
fn new_receiver<T>(shared: Arc<Shared<T>>) -> Receiver<T> {
let mut tail = shared.tail.lock();
if tail.rx_cnt == MAX_RECEIVERS {
panic!("max receivers");
}
tail.rx_cnt = tail.rx_cnt.checked_add(1).expect("overflow");
let next = tail.pos;
drop(tail);
Receiver { shared, next }
}
impl Tail { impl Tail {
fn notify_rx(&mut self) { fn notify_rx(&mut self) {
while let Some(mut waiter) = self.waiters.pop_back() { while let Some(mut waiter) = self.waiters.pop_back() {
@@ -980,6 +985,13 @@ impl<T: Clone> Receiver<T> {
} }
} }
impl<T> Clone for Receiver<T> {
fn clone(&self) -> Self {
let shared = self.shared.clone();
new_receiver(shared)
}
}
impl<T> Drop for Receiver<T> { impl<T> Drop for Receiver<T> {
fn drop(&mut self) { fn drop(&mut self) {
let mut tail = self.shared.tail.lock(); let mut tail = self.shared.tail.lock();
+2 -1
View File
@@ -92,11 +92,12 @@ fn broadcast_two() {
}); });
} }
// Exercise the Receiver Clone impl as well
#[test] #[test]
fn broadcast_wrap() { fn broadcast_wrap() {
loom::model(|| { loom::model(|| {
let (tx, mut rx1) = broadcast::channel(2); let (tx, mut rx1) = broadcast::channel(2);
let mut rx2 = tx.subscribe(); let mut rx2 = rx1.clone();
let th1 = thread::spawn(move || { let th1 = thread::spawn(move || {
block_on(async { block_on(async {