tg_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}