crossbeam-channel之waker学习

本文详细解析了crossbeam_channel库中的休眠唤醒机制,重点关注Waker和SyncWaker结构,以及在读写操作中的唤醒与阻塞逻辑,阐述了如何通过try_select和unpark函数实现线程同步。
摘要由CSDN通过智能技术生成

crossbeam-channel休眠唤醒–阻塞等待

查看crossbeam_channel休眠唤醒机制,可以看出涉及休眠唤醒的主要源码在waker.rs文件中。

/// Represents a thread blocked on a specific channel operation.
pub(crate) struct Entry {
    /// The operation.
    pub(crate) oper: Operation,

    /// Optional packet.
    pub(crate) packet: *mut (),

    /// Context associated with the thread owning this operation.
    pub(crate) cx: Context,
}

/// A queue of threads blocked on channel operations.
///
/// This data structure is used by threads to register blocking operations and get woken up once
/// an operation becomes ready.
pub(crate) struct Waker {
    /// A list of select operations.
    selectors: Vec<Entry>,

    /// A list of operations waiting to be ready.
    observers: Vec<Entry>,
}

/// A waker that can be shared among threads without locking.
///
/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization.
pub(crate) struct SyncWaker {
    /// The inner `Waker`.
    inner: Mutex<Waker>,

    /// `true` if the waker is empty.
    is_empty: AtomicBool,
}

主要结构体如上。

创建注册机制:

唤醒机制:

例如,在channel为array情况下,当channel读取操作read时,会唤醒发送者sender,例如,self.senders.notify();其中senders为 SyncWaker类型。唤醒过程如下:

pub(crate) fn notify(&self)impl SyncWaker
--> pub(crate) fn notify(&mut self): impl Waker
    --> entry.cx.try_select(Selected::Operation(entry.oper)).is_ok()
            |
            |--> pub fn try_select(&self, select: Selected) -> Result<(), Selected>:crossbeam-channel/src/context.rs
            | 在try_select内部主要是操作inner.select状态,比较他的值与Selected::Waiting.into(),进行原子操作
        --> entry.cx.unpark(); 
            --> self.inner.thread.unpark();实际上还是操作的thread的unpark函数。
        

同理,在write的时候如果写入成功,也会唤醒对端的接收事件self.receivers.notify()。

阻塞机制:

pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> 
--> self.receivers.register(oper, cx);//先注册
--> let sel = cx.wait_until(deadline);
    --> pub fn wait_until(&self, deadline: Option<Instant>) -> Selected :crossbeam-channel/src/context.rs
        --> return match self.try_select(Selected::Aborted)
        --> thread::park(); // 这个就是当前线程park

可以发现都会在实际不同情况进入context的 try_select方法,所以可以详细分析具体代码逻辑。

    pub fn try_select(&self, select: Selected) -> Result<(), Selected> {
        self.inner
            .select
            .compare_exchange(
                Selected::Waiting.into(),
                select.into(),
                Ordering::AcqRel,
                Ordering::Acquire,
            )
            .map(|_| ())
            .map_err(|e| e.into())
    }

同理,在发送send操作的过程中,也会如上进行操作注册,然后如果满足阻塞条件,就会阻塞线程。

也就是实际就是在读写过程中主要实现唤醒操作,在发送和接收过程中实现阻塞操作。这个逻辑其实就是,当你写入数据到channel中时,写入成功即唤醒接收者接收。当接收者接收数据时,如果接收数据失败且满足阻塞条件,则阻塞当前线程,直到被唤醒或者超时。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值