github.com/sunvim/utils@v0.1.0/queue/queue.go (about) 1 package queue 2 3 import ( 4 "runtime" 5 "sync" 6 "sync/atomic" 7 "time" 8 9 "gopkg.in/eapache/queue.v1" 10 ) 11 12 // Queue queue 13 type Queue struct { 14 sync.Mutex 15 popable *sync.Cond 16 buffer *queue.Queue 17 closed bool 18 count int32 19 cc chan interface{} 20 once sync.Once 21 } 22 23 // New 24 func New() *Queue { 25 ch := &Queue{ 26 buffer: queue.New(), 27 } 28 ch.popable = sync.NewCond(&ch.Mutex) 29 return ch 30 } 31 32 // Pop 33 func (q *Queue) Pop() (v interface{}) { 34 c := q.popable 35 36 q.Mutex.Lock() 37 defer q.Mutex.Unlock() 38 39 for q.Len() == 0 && !q.closed { 40 c.Wait() 41 } 42 43 if q.closed { 44 return 45 } 46 47 if q.Len() > 0 { 48 buffer := q.buffer 49 v = buffer.Peek() 50 buffer.Remove() 51 atomic.AddInt32(&q.count, -1) 52 } 53 return 54 } 55 56 // TryPop 57 func (q *Queue) TryPop() (v interface{}, ok bool) { 58 buffer := q.buffer 59 60 q.Mutex.Lock() 61 defer q.Mutex.Unlock() 62 63 if q.Len() > 0 { 64 v = buffer.Peek() 65 buffer.Remove() 66 atomic.AddInt32(&q.count, -1) 67 ok = true 68 } else if q.closed { 69 ok = true 70 } 71 72 return 73 } 74 75 // TryPopTimeout 76 func (q *Queue) TryPopTimeout(tm time.Duration) (v interface{}, ok bool) { 77 q.once.Do(func() { 78 q.cc = make(chan interface{}, 1) 79 }) 80 go func() { 81 q.popChan(&q.cc) 82 }() 83 84 ok = true 85 timeout := time.After(tm) 86 select { 87 case v = <-q.cc: 88 case <-timeout: 89 if !q.closed { 90 q.popable.Signal() 91 } 92 ok = false 93 } 94 95 return 96 } 97 98 // Pop 99 func (q *Queue) popChan(v *chan interface{}) { 100 c := q.popable 101 102 q.Mutex.Lock() 103 defer q.Mutex.Unlock() 104 105 for q.Len() == 0 && !q.closed { 106 c.Wait() 107 } 108 109 if q.closed { 110 *v <- nil 111 return 112 } 113 114 if q.Len() > 0 { 115 buffer := q.buffer 116 tmp := buffer.Peek() 117 buffer.Remove() 118 atomic.AddInt32(&q.count, -1) 119 *v <- tmp 120 } else { 121 *v <- nil 122 } 123 return 124 } 125 126 // Push 127 func (q *Queue) Push(v interface{}) { 128 q.Mutex.Lock() 129 defer q.Mutex.Unlock() 130 if !q.closed { 131 q.buffer.Add(v) 132 atomic.AddInt32(&q.count, 1) 133 q.popable.Signal() 134 } 135 } 136 137 // Len 138 func (q *Queue) Len() int { 139 return (int)(atomic.LoadInt32(&q.count)) 140 } 141 142 // Close Queue 143 // After close, Pop will return nil without block, and TryPop will return v=nil, ok=True 144 func (q *Queue) Close() { 145 q.Mutex.Lock() 146 defer q.Mutex.Unlock() 147 if !q.closed { 148 q.closed = true 149 atomic.StoreInt32(&q.count, 0) 150 q.popable.Broadcast() 151 } 152 } 153 154 // IsClose check is closed 155 func (q *Queue) IsClose() bool { 156 return q.closed 157 } 158 159 // Wait 160 func (q *Queue) Wait() { 161 for { 162 if q.closed || q.Len() == 0 { 163 break 164 } 165 166 runtime.Gosched() 167 } 168 }