Rust源码分析:channel内部mpsc队列

爷,独闯天下 提交于 2020-07-27 23:10:13

https://zhuanlan.zhihu.com/p/50176724

接着前面的channel的升级继续讲。

首先,之前的upgrade过程中内存的回收要稍微注意下。因为Receiver现在指向shared::Packet之后,那个new_port需要被析构,也就是调用drop函数,我们看下drop的实现:

impl<T> Drop for Receiver<T> {  fn drop(&mut self) {  match *unsafe { self.inner() } {  Flavor::Oneshot(ref p) => p.drop_port(),  Flavor::Stream(ref p) => p.drop_port(),  Flavor::Shared(ref p) => p.drop_port(),  Flavor::Sync(ref p) => p.drop_port(),  }  } }

由于之前的swap操作,走Flavor::Oneshot路径:

    pub fn drop_port(&self) {  match self.state.swap(DISCONNECTED, Ordering::SeqCst) {  // An empty channel has nothing to do, and a remotely disconnected  // channel also has nothing to do b/c we're about to run the drop  // glue  DISCONNECTED | EMPTY => {}   // There's data on the channel, so make sure we destroy it promptly.  // This is why not using an arc is a little difficult (need the box  // to stay valid while we take the data).  DATA => unsafe { (&mut *self.data.get()).take().unwrap(); },   // We're the only ones that can block on this port  _ => unreachable!()  }  }

同样是DISCONNECTED替换DISCONNECTED而已,没有过多操作。

同时不再需要的oneshot::Packet也要被析构:

impl<T> Drop for Packet<T> {  fn drop(&mut self) {  assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);  } }

只是个DISCONNECTED的检验操作。

所以现在Sender/Receiver都存放了Flavor::Shared(Arc<shared::Packet<T>>),之前的Flavor::Oneshot(Arc<oneshot::Packet<T>>>和临时产生的Sender/Receiver都不存在了。

并发队列

所以我们接着关注内在的数据结构,通过跟踪以下函数来分析:

  • Sender::send(&self, t: T)
  • Receiver::recv(&self)
  • Receiver::recv_timeout(&self, timeout: Duration)

Sender::send(&self, t: T):

    pub fn send(&self, t: T) -> Result<(), SendError<T>> {  let (new_inner, ret) = match *unsafe { self.inner() } {  Flavor::Oneshot(ref p) => {  if !p.sent() {  return p.send(t).map_err(SendError);  } else {  let a = Arc::new(stream::Packet::new());  let rx = Receiver::new(Flavor::Stream(a.clone()));  match p.upgrade(rx) {  oneshot::UpSuccess => {  let ret = a.send(t);  (a, ret)  }  oneshot::UpDisconnected => (a, Err(t)),  oneshot::UpWoke(token) => {  // This send cannot panic because the thread is  // asleep (we're looking at it), so the receiver  // can't go away.  a.send(t).ok().unwrap();  token.signal();  (a, Ok(()))  }  }  }  }  Flavor::Stream
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!