1- use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
1+ use std:: sync:: atomic:: { AtomicU32 , AtomicUsize , Ordering } ;
22
33use atomic_wait:: { wait, wake_all, wake_one} ;
44
55use crate :: MutexGuard ;
66
77pub struct Condvar {
88 counter : AtomicU32 ,
9+ num_waiters : AtomicUsize ,
910}
1011
1112impl Condvar {
1213 pub const fn new ( ) -> Self {
1314 Self {
1415 counter : AtomicU32 :: new ( 0 ) ,
16+ num_waiters : AtomicUsize :: new ( 0 ) ,
1517 }
1618 }
1719
1820 pub fn notify_one ( & self ) {
19- self . counter . fetch_add ( 1 , Ordering :: Relaxed ) ;
20- wake_one ( & self . counter ) ;
21+ if self . num_waiters . load ( Ordering :: Relaxed ) > 0 {
22+ self . counter . fetch_add ( 1 , Ordering :: Relaxed ) ;
23+ wake_one ( & self . counter ) ;
24+ }
2125 }
2226
2327 pub fn notify_all ( & self ) {
24- self . counter . fetch_add ( 1 , Ordering :: Relaxed ) ;
25- wake_all ( & self . counter ) ;
28+ if self . num_waiters . load ( Ordering :: Relaxed ) > 0 {
29+ self . counter . fetch_add ( 1 , Ordering :: Relaxed ) ;
30+ wake_all ( & self . counter ) ;
31+ }
2632 }
2733
2834 pub fn wait < ' a , T > ( & self , guard : MutexGuard < ' a , T > ) -> MutexGuard < ' a , T > {
35+ self . num_waiters . fetch_add ( 1 , Ordering :: Relaxed ) ;
2936 let counter_value = self . counter . load ( Ordering :: Relaxed ) ;
3037
3138 // Unlock the mutex by dropping the guard,
@@ -36,6 +43,8 @@ impl Condvar {
3643 // Wait, but only if the counter hasn't changed since unlocking.
3744 wait ( & self . counter , counter_value) ;
3845
46+ self . num_waiters . fetch_sub ( 1 , Ordering :: Relaxed ) ;
47+
3948 // If the condition matches, lock the mutex and do biz logic.
4049 mutex. lock ( )
4150 }
0 commit comments