github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/execqueue.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:38</date> 10 //</624450093465997312> 11 12 13 package les 14 15 import "sync" 16 17 //execqueue实现在单个线程中执行函数调用的队列, 18 //与排队的顺序相同。 19 type execQueue struct { 20 mu sync.Mutex 21 cond *sync.Cond 22 funcs []func() 23 closeWait chan struct{} 24 } 25 26 //NeXeExcel队列创建一个新的执行队列。 27 func newExecQueue(capacity int) *execQueue { 28 q := &execQueue{funcs: make([]func(), 0, capacity)} 29 q.cond = sync.NewCond(&q.mu) 30 go q.loop() 31 return q 32 } 33 34 func (q *execQueue) loop() { 35 for f := q.waitNext(false); f != nil; f = q.waitNext(true) { 36 f() 37 } 38 close(q.closeWait) 39 } 40 41 func (q *execQueue) waitNext(drop bool) (f func()) { 42 q.mu.Lock() 43 if drop { 44 //删除刚刚执行的函数。我们在这里而不是在什么时候 45 //出列so len(q.funcs)包括正在运行的函数。 46 q.funcs = append(q.funcs[:0], q.funcs[1:]...) 47 } 48 for !q.isClosed() { 49 if len(q.funcs) > 0 { 50 f = q.funcs[0] 51 break 52 } 53 q.cond.Wait() 54 } 55 q.mu.Unlock() 56 return f 57 } 58 59 func (q *execQueue) isClosed() bool { 60 return q.closeWait != nil 61 } 62 63 //如果可以向执行队列中添加更多函数调用,则can queue返回true。 64 func (q *execQueue) canQueue() bool { 65 q.mu.Lock() 66 ok := !q.isClosed() && len(q.funcs) < cap(q.funcs) 67 q.mu.Unlock() 68 return ok 69 } 70 71 //queue向执行队列添加函数调用。如果成功,则返回true。 72 func (q *execQueue) queue(f func()) bool { 73 q.mu.Lock() 74 ok := !q.isClosed() && len(q.funcs) < cap(q.funcs) 75 if ok { 76 q.funcs = append(q.funcs, f) 77 q.cond.Signal() 78 } 79 q.mu.Unlock() 80 return ok 81 } 82 83 //quit停止执行队列。 84 //quit在返回之前等待当前执行完成。 85 func (q *execQueue) quit() { 86 q.mu.Lock() 87 if !q.isClosed() { 88 q.closeWait = make(chan struct{}) 89 q.cond.Signal() 90 } 91 q.mu.Unlock() 92 <-q.closeWait 93 } 94