v2 / vlib / sync / cond.v
87 lines · 79 sloc · 1.82 KB · 6b45931598fd8e405fd53f8fa35d72be639b73e1
Raw
1module sync
2
3@[heap]
4pub struct Cond {
5mut:
6 // Externally provided mutex for shared resource protection
7 mutex &Mutex
8 // Internal lock for protecting wait queue access
9 inner_mutex Mutex
10 // Queue of waiting channels
11 waiters []chan bool
12}
13
14// new_cond creates new condition variable associated with given mutex
15pub fn new_cond(m &Mutex) &Cond {
16 return &Cond{
17 mutex: m
18 inner_mutex: new_mutex()
19 waiters: []chan bool{}
20 }
21}
22
23// wait waits for condition notification.
24// NOTE: Spurious wakeups are possible; always use in a loop:
25// mutex.lock()
26// for !condition {
27// cond.wait()
28// }
29// mutex.unlock()
30@[direct_array_access]
31pub fn (mut c Cond) wait() {
32 // Create a channel for this waiting operation with capacity 1
33 ch := chan bool{cap: 1}
34 defer {
35 ch.close()
36 }
37
38 // Add this channel to the waiters queue
39 c.inner_mutex.lock()
40 c.waiters << ch
41 c.inner_mutex.unlock()
42
43 // Release external lock and suspend
44 c.mutex.unlock()
45 _ := <-ch // Block until signaled
46
47 c.inner_mutex.lock()
48 for i := c.waiters.len - 1; i >= 0; i-- {
49 if c.waiters[i] == ch {
50 c.waiters.delete(i)
51 break
52 }
53 }
54 c.inner_mutex.unlock()
55 // Re-acquire external lock before returning
56 c.mutex.lock()
57}
58
59// signal wakes one waiting thread.
60@[direct_array_access]
61pub fn (mut c Cond) signal() {
62 c.inner_mutex.lock()
63 defer { c.inner_mutex.unlock() }
64 if c.waiters.len > 0 {
65 // Remove first waiter from queue
66 mut waiter := c.waiters[0]
67 c.waiters.delete(0)
68 if !waiter.closed {
69 waiter <- true // Wake up the thread
70 }
71 }
72}
73
74// broadcast wakes all waiting threads.
75@[direct_array_access]
76pub fn (mut c Cond) broadcast() {
77 c.inner_mutex.lock()
78 defer { c.inner_mutex.unlock() }
79 // Release all waiting ch
80 for i in 0 .. c.waiters.len {
81 mut waiter := c.waiters[i]
82 if !waiter.closed {
83 waiter <- true // Wake up the thread
84 }
85 }
86 c.waiters.clear()
87}
88