Skip to content

Commit 4e403e9

Browse files
committed
feat(condvar): optimize condition varbiable to avoid syscall when no waiting threads
1 parent 56a6ef1 commit 4e403e9

1 file changed

Lines changed: 14 additions & 5 deletions

File tree

src/condvar.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,38 @@
1-
use std::sync::atomic::{AtomicU32, Ordering};
1+
use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
22

33
use atomic_wait::{wait, wake_all, wake_one};
44

55
use crate::MutexGuard;
66

77
pub struct Condvar {
88
counter: AtomicU32,
9+
num_waiters: AtomicUsize,
910
}
1011

1112
impl 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

Comments
 (0)