Skip to main content

tg_rcore_tutorial_sync/
condvar.rs

1use super::{Mutex, UPIntrFreeCell};
2use alloc::{collections::VecDeque, sync::Arc};
3use tg_task_manage::ThreadId;
4
5/// Condvar
6pub struct Condvar {
7    /// UPIntrFreeCell<CondvarInner>
8    pub inner: UPIntrFreeCell<CondvarInner>,
9}
10
11/// CondvarInner
12pub struct CondvarInner {
13    /// block queue
14    pub wait_queue: VecDeque<ThreadId>,
15}
16
17impl Condvar {
18    /// 创建一个新的条件变量。
19    pub fn new() -> Self {
20        Self {
21            // SAFETY: 此条件变量仅在单处理器内核环境中使用
22            inner: unsafe {
23                UPIntrFreeCell::new(CondvarInner {
24                    wait_queue: VecDeque::new(),
25                })
26            },
27        }
28    }
29    /// 唤醒某个阻塞在当前条件变量上的线程
30    pub fn signal(&self) -> Option<ThreadId> {
31        let mut inner = self.inner.exclusive_access();
32        inner.wait_queue.pop_front()
33    }
34
35    /*
36    pub fn wait(&self) {
37        let mut inner = self.inner.exclusive_access();
38        inner.wait_queue.push_back(current_task().unwrap());
39        drop(inner);
40        block_current_and_run_next();
41    }
42    */
43    /// 将当前线程阻塞在条件变量上
44    pub fn wait_no_sched(&self, tid: ThreadId) -> bool {
45        self.inner.exclusive_session(|inner| {
46            inner.wait_queue.push_back(tid);
47        });
48        false
49    }
50    /// 从 mutex 的锁中释放一个线程,并将其阻塞在条件变量的等待队列中,等待其他线程运行完毕,当前的线程再试图获取这个锁
51    ///
52    /// 注意:下面是简化版的实现,在 mutex 唤醒一个线程之后,当前线程就直接获取这个 mutex,不管能不能获取成功
53    /// 这里是单纯为了过测例,
54    pub fn wait_with_mutex(
55        &self,
56        tid: ThreadId,
57        mutex: Arc<dyn Mutex>,
58    ) -> (bool, Option<ThreadId>) {
59        // 教学提示:标准条件变量语义应包含“原子地解锁 + 入队 + 睡眠 + 被唤醒后重试加锁”。
60        // 此处为教学简化实现,便于在章节中聚焦主流程。
61        let waking_tid = mutex.unlock().unwrap();
62        (mutex.lock(tid), Some(waking_tid))
63    }
64}