diff --git a/decorators_test.go b/decorators_test.go index 00275ab..12927ef 100644 --- a/decorators_test.go +++ b/decorators_test.go @@ -182,7 +182,7 @@ } for _, columnCase := range testCases { - mpb.SyncWidth(toSyncMatrix(columnCase)) + mpb.SyncWidth(toSyncMatrix(columnCase), nil) var results []chan string for _, step := range columnCase { step := step diff --git a/heap_manager.go b/heap_manager.go index 09cdf66..670f276 100644 --- a/heap_manager.go +++ b/heap_manager.go @@ -65,8 +65,9 @@ sync = false l = bHeap.Len() } - syncWidth(pMatrix) - syncWidth(aMatrix) + drop := req.data.(<-chan struct{}) + syncWidth(pMatrix, drop) + syncWidth(aMatrix, drop) case h_iter: data := req.data.(iterData) for _, b := range bHeap { @@ -104,8 +105,8 @@ } } -func (m heapManager) sync() { - m <- heapRequest{cmd: h_sync} +func (m heapManager) sync(drop <-chan struct{}) { + m <- heapRequest{cmd: h_sync, data: drop} } func (m heapManager) push(b *Bar, sync bool) { @@ -135,17 +136,22 @@ m <- heapRequest{cmd: h_end, data: ch} } -func syncWidth(matrix map[int][]chan int) { +func syncWidth(matrix map[int][]chan int, drop <-chan struct{}) { for _, column := range matrix { - go maxWidthDistributor(column) + go maxWidthDistributor(column, drop) } } -func maxWidthDistributor(column []chan int) { +func maxWidthDistributor(column []chan int, drop <-chan struct{}) { var maxWidth int for _, ch := range column { - if w := <-ch; w > maxWidth { - maxWidth = w + select { + case w := <-ch: + if w > maxWidth { + maxWidth = w + } + case <-drop: + return } } for _, ch := range column { diff --git a/progress.go b/progress.go index b7ede07..2e38a15 100644 --- a/progress.go +++ b/progress.go @@ -34,9 +34,10 @@ // pState holds bars in its priorityQueue, it gets passed to (*Progress).serve monitor goroutine. type pState struct { - ctx context.Context - hm heapManager - rows []io.Reader + ctx context.Context + hm heapManager + dropS, dropD chan struct{} + rows []io.Reader // following are provided/overrided by user refreshRate time.Duration @@ -69,6 +70,8 @@ s := &pState{ ctx: ctx, hm: make(heapManager), + dropS: make(chan struct{}), + dropD: make(chan struct{}), rows: make([]io.Reader, 32), refreshRate: defaultRefreshRate, popPriority: math.MinInt32, @@ -300,10 +303,13 @@ } func (s *pState) render(cw *cwriter.Writer) (err error) { + s.hm.sync(s.dropS) + var width, height int if cw.IsTerminal() { width, height, err = cw.GetTermSize() if err != nil { + close(s.dropS) return err } } else { @@ -315,7 +321,6 @@ height = 100 } - s.hm.sync() iter := make(chan *Bar) s.hm.iter(iter, nil) for b := range iter { @@ -331,14 +336,14 @@ var popCount int - iter, drop := make(chan *Bar), make(chan struct{}) - s.hm.drain(iter, drop) + iter := make(chan *Bar) + s.hm.drain(iter, s.dropD) s.rows = s.rows[:0] for b := range iter { frame := <-b.frameCh if frame.err != nil { - close(drop) + close(s.dropD) b.cancel() return frame.err // b.frameCh is buffered it's ok to return here }