Hi everyone,
I found myself needing an adaptive async barrier and I came up with the following code. Given the complexity of reasoning on concurrent code I wanted to check with you:
- That it is indeed sound. I think it is if one accepts that panic do not poison the barrier.
- Do you have any idea how much of a performance hit I am incurring comparing to an hypothetic "ideal" implementation?
Thanks
The code
use tokio::sync::broadcast::{Sender, error::RecvError, channel};
#[derive(Debug, Clone, Copy)]
enum Empty {}
#[derive(Debug, Clone)]
pub(crate) struct Barrier {
inner: Sender<Empty>,
}
impl Barrier {
pub(crate) async fn wait(self) {
let mut receiver = self.inner.subscribe();
drop(self.inner);
match receiver.recv().await {
Ok(_) => unreachable!(),
Err(RecvError::Lagged(_)) => unreachable!(),
Err(RecvError::Closed) => ()
}
}
pub(crate) fn new() -> Self {
Self {
inner: channel(1).0
}
}
}